0% found this document useful (0 votes)
2 views19 pages

Multithreading in Java

Multithreading in Java allows multiple threads to execute simultaneously, sharing memory and resources, which is more efficient than multiprocessing. Key advantages include non-blocking user experience, time savings, and independent thread execution. The document also covers thread lifecycle, creation methods, scheduling, and the role of daemon threads in Java's memory management through garbage collection.

Uploaded by

Nagothi Sailaja
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
0% found this document useful (0 votes)
2 views19 pages

Multithreading in Java

Multithreading in Java allows multiple threads to execute simultaneously, sharing memory and resources, which is more efficient than multiprocessing. Key advantages include non-blocking user experience, time savings, and independent thread execution. The document also covers thread lifecycle, creation methods, scheduling, and the role of daemon threads in Java's memory management through garbage collection.

Uploaded by

Nagothi Sailaja
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1/ 19

Multithreading in Java

Multithreading in Java is a process of executing multiple threads simultaneously.

A thread is a lightweight sub-process, the smallest unit of processing. Multiprocessing and


multithreading, both are used to achieve multitasking.

However, we use multithreading than multiprocessing because threads use a shared memory area.
They don't allocate separate memory area so saves memory,

Advantages of Java Multithreading

1) It doesn't block the user because threads are independent and you can perform multiple
operations at the same time.

2) You can perform many operations together, so it saves time.

3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single
thread.

Process

A process is an instance of a running program. When you open an application (like a browser or text
editor), it creates a process in your computer's memory. Each process runs independently and has its
own memory and resources.

Thread

A thread is the smallest unit of a process that can execute code. A process can have multiple threads,
each performing a different task simultaneously within the same process memory

EXAMPLE

Process

Imagine Microsoft Word is a process. When you open the Microsoft Word application, your
computer creates a new process for it. This process is independent and has its own allocated
memory and resources, like the toolbar, fonts, and document editor.

Think of this process as the overall workspace where you’re working on a document.

Thread

Inside the Microsoft Word process, there are different threads handling separate tasks
simultaneously:

 Typing Thread: One thread handles typing, making sure letters appear on the screen as you
type.

 Spell Check Thread: Another thread continuously checks for spelling and grammar errors.

 Auto-Save Thread: Another thread runs in the background to save your work automatically
at intervals.

Multitasking

Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to utilize


the CPU. Multitasking can be achieved in two ways:
o Process-based Multitasking (Multiprocessing)

o Thread-based Multitasking (Multithreading)

Process-based Multitasking (Multiprocessing)

o Each process has an address in memory. In other words, each process allocates a separate
memory area.

o A process is heavyweight.

o Cost of communication between the process is high.

o Switching from one process to another requires some time for saving and loading registers,
memory maps, updating lists, etc.

Ex:

Multiprocessing refers to the ability of a computer system to run multiple processes


simultaneously. This approach is common in modern computing, where a system has multiple
CPU cores, each capable of running a separate process independently of others. Multiprocessing
increases efficiency and speeds up tasks by using multiple CPU cores to handle different
processes at the same time.

Example of Multiprocessing

Imagine you’re using your computer to:

1. Stream music.

2. Download a large file.

3. Edit a document in a text editor.

In a multiprocessing system, each of these tasks (streaming, downloading, and editing) could run
in separate processes on different CPU cores. This way, each process runs independently without
slowing down or interfering with each other, allowing you to multitask smoothly.

2) Thread-based Multitasking (Multithreading)

o Threads share the same address space.

o A thread is lightweight.

o Cost of communication between the thread is low.


As shown in the above figure, a thread is executed inside the process. There is context-switching
between the threads. There can be multiple processes inside the OS, and one process can have
multiple threads.

he Thread Life Cycle in Java (or most programming languages) represents the different stages a
thread goes through from creation to termination. Here’s a breakdown of each stage with a simple
explanation:

1. New (or Born)

 Description: When a thread is created but hasn’t started yet, it’s in the New state.

 Example: Thread t = new Thread(); — here, t is a new thread.

2. Runnable

 Description: When a thread’s start() method is called, it enters the Runnable state.

 Example: t.start(); — the thread t is now ready to run.

3. Blocked

 Description: If a thread tries to enter a synchronized block but another thread holds the lock,
it enters the Blocked state.

4. Waiting

 Description: A thread is in the Waiting state when it’s paused, waiting for some other thread
to perform a specific action (like notify it).

5. Timed Waiting

 Description: A thread is in Timed Waiting if it’s waiting for a specific period.

 Example: sleep(1000); (waits for 1 second), wait(2000); (waits for 2 seconds).


6. Terminated (or Dead)

 Description: Once a thread finishes executing (either by completing its task or due to an
unhandled exception), it enters the Terminated state.

Visual Summary

 New → Runnable → (can enter Blocked, Waiting, or Timed Waiting) → Terminated

Java Threads | How to create a thread in Java

There are two ways to create a thread:

1. By extending Thread class

2. By implementing Runnable interface.

Thread class:

Thread class provide constructors and methods to create and perform operations on a thread.Thread
class extends Object class and implements Runnable interface.

1. class Multi extends Thread{

2. public void run(){

3. System.out.println("thread is running...");

4. }

5. public static void main(String args[]){

6. Multi t1=new Multi();

7. t1.start();

8. }

9. }

Commonly used methods of Thread class:

1. public void run(): is used to perform action for a thread.

2. public void start(): starts the execution of the thread.JVM calls the run() method on the
thread.

3. public void sleep(long miliseconds): Causes the currently executing thread to sleep
(temporarily cease execution) for the specified number of milliseconds.

4. public void join(): waits for a thread to die.

5. public void join(long miliseconds): waits for a thread to die for the specified miliseconds.

6. public int getPriority(): returns the priority of the thread.


7. public int setPriority(int priority): changes the priority of the thread.

8. public String getName(): returns the name of the thread.

9. public void setName(String name): changes the name of the thread.

10. public Thread currentThread(): returns the reference of currently executing thread.

11. public int getId(): returns the id of the thread.

12. public Thread.State getState(): returns the state of the thread.

13. public boolean isAlive(): tests if the thread is alive.

14. public void yield(): causes the currently executing thread object to temporarily pause and
allow other threads to execute.

15. public void suspend(): is used to suspend the thread(depricated).

16. public void resume(): is used to resume the suspended thread(depricated).

17. public void stop(): is used to stop the thread(depricated).

18. public boolean isDaemon(): tests if the thread is a daemon thread.

19. public void setDaemon(boolean b): marks the thread as daemon or user thread.

20. public void interrupt(): interrupts the thread.

21. public boolean isInterrupted(): tests if the thread has been interrupted.

22. public static boolean interrupted(): tests if the current thread has been interrupted.

Runnable interface:

The Runnable interface should be implemented by any class whose instances are intended to be
executed by a thread. Runnable interface have only one method named run().

1. public void run(): is used to perform action for a thread.

1. class Multi3 implements Runnable{

2. public void run(){

3. System.out.println("thread is running...");

4. }

5.

6. public static void main(String args[]){

7. Multi3 m1=new Multi3();

8. Thread t1 =new Thread(m1); // Using the constructor Thread(Runnable r)

9. t1.start();
10. }

11. }

Note : A class implementing the Runnable interface does not execute on its own because the
Runnable interface only defines the task (in the run() method), but it doesn't have the capability to
manage or start the thread. You must pass the Runnable object to a Thread object, which is
responsible for managing and starting the thread.

Without creating a Thread object and calling its start() method, the task in the run() method will not
be executed, as the Thread class

Thread Scheduler in Java

A component of Java that decides which thread to run or execute and which thread to wait is called
a thread scheduler in Java. In Java, a thread is only chosen by a thread scheduler if it is in the
runnable state. However, if there is more than one thread in the runnable state, it is up to the thread
scheduler to pick one of the threads and ignore the other ones. There are some criteria that decide
which thread will execute first. There are two factors for scheduling a thread i.e. Priority and Time of
arrival.

Priority: Priority of each thread lies between 1 to 10. If a thread has a higher priority, it means that
thread has got a better chance of getting picked up by the thread scheduler.

Time of Arrival: Suppose two threads of the same priority enter the runnable state, then priority
cannot be the factor to pick a thread from these two threads. In such a case, arrival time of thread is
considered by the thread scheduler. A thread that arrived first gets the preference over the other
threads.

Thread.sleep()

The method sleep() is being used to halt the working of a thread for a given amount of time. The
time up to which the thread remains in the sleeping state is known as the sleeping time of the
thread. After the sleeping time is over, the thread starts its execution from where it has left.

Can we start a thread twice

No. After starting a thread, it can never be started again. If you does so,
an IllegalThreadStateException is thrown. In such case, thread will run once but for second time, it
will throw exception.

What if we call Java run() method directly instead start() method?

If you directly call the run() method in Java instead of the start() method, it will not start a new
thread. Instead, the run() method will execute on the current thread (the thread that calls it) like a
regular method, which defeats the purpose of using threads for concurrent execution.
join()

The join() method in Java is used to pause the execution of the current thread until the thread on
which join() is called has finished its execution. In simpler terms, it allows one thread to wait for
another thread to complete before continuing its execution.

Why is join() used?

 Thread Synchronization: It ensures that one thread finishes its task before another thread
starts or continues.

 Order of Execution: When you need to control the order of execution of threads (for
example, waiting for one thread to finish before proceeding with another.

class MyTask implements Runnable {

@Override

public void run() {

try {

// Simulating some work

Thread.sleep(1000);

System.out.println(Thread.currentThread().getName() + " has finished.");

} catch (InterruptedException e) {

e.printStackTrace();

public class Main {

public static void main(String[] args) throws InterruptedException {

MyTask task = new MyTask();

// Creating two threads

Thread t1 = new Thread(task, "Thread 1");

Thread t2 = new Thread(task, "Thread 2");

// Starting threads

t1.start();
t2.start();

// Calling join() to make the main thread wait until t1 and t2 finish

t1.join(); // Main thread waits for t1 to finish

t2.join(); // Main thread waits for t2 to finish

System.out.println("Main thread has finished.");

Output:

plaintext

Copy code

Thread 1 has finished.

Thread 2 has finished.

Main thread has finished.

Naming Thread

The Thread class provides methods to change and get the name of a thread. By default, each thread
has a name, i.e. thread-0, thread-1 and so on. By we can change the name of the thread by using the
setName() method. The syntax of setName() and getName() methods are given below:

1. public String getName(): is used to return the name of a thread.

2. public void setName(String name): is used to change the name of a thread.

Priority of a Thread (Thread Priority)

Each thread has a priority. Priorities are represented by a number between 1 and 10.

Setter & Getter Method of Thread Priority

Let's discuss the setter and getter method of the thread priority.

public final int getPriority(): The java.lang.Thread.getPriority() method returns the priority of the
given thread.

public final void setPriority(int newPriority): The java.lang.Thread.setPriority() method updates or


assign the priority of the thread to newPriority. The method throws IllegalArgumentException if the
value newPriority goes out of the range, which is 1 (minimum) to 10 (maximum).

3 constants defined in Thread class:


1. public static int MIN_PRIORITY

2. public static int NORM_PRIORITY

3. public static int MAX_PRIORITY

Default priority of a thread is 5 (NORM_PRIORITY). The value of MIN_PRIORITY is 1 and the value of
MAX_PRIORITY is 10.

Daemon Thread in Java

Daemon thread in Java is a service provider thread that provides services to the user thread. Its life
depend on the mercy of user threads i.e. when all the user threads dies, JVM terminates this thread
automatically.

There are many java daemon threads running automatically e.g. gc, finalizer etc.

Points to remember for Daemon Thread in Java

 It provides services to user threads for background supporting tasks. It has no role in life than
to serve user threads.

 Its life depends on user threads.

 It is a low priority thread.

Why JVM terminates the daemon thread if there is no user thread?

The sole purpose of the daemon thread is that it provides services to user thread for background
supporting task. If there is no user thread, why should JVM keep running this thread. That is why JVM
terminates the daemon thread if there is no user thread.

Methods for Java Daemon thread by Thread class

The java.lang.Thread class provides two methods for java daemon thread.

No. Method Description

is used to mark the current


public void setDaemon(boolean
1) thread as daemon thread or user
status)
thread.

is used to check that current is


2) public boolean isDaemon()
daemon.

Simple example of Daemon thread in java

File: MyThread.java

1. public class TestDaemonThread1 extends Thread{

2. public void run(){

3. if(Thread.currentThread().isDaemon()){//checking for daemon thread


4. System.out.println("daemon thread work");

5. }

6. else{

7. System.out.println("user thread work");

8. }

9. }

10. public static void main(String[] args){

11. TestDaemonThread1 t1=new TestDaemonThread1();//creating thread

12. TestDaemonThread1 t2=new TestDaemonThread1();

13. TestDaemonThread1 t3=new TestDaemonThread1();

14.

15. t1.setDaemon(true);//now t1 is daemon thread

16.

17. t1.start();//starting threads

18. t2.start();

19. t3.start();

20. }

21. }

Test it Now

Output:

daemon thread work

user thread work

user thread work

Note: If you want to make a user thread as Daemon, it must not be started otherwise it will throw
IllegalThreadStateException.

1. t1.start();

2. t1.setDaemon(true);//will throw exception here


Java Garbage Collection

In java, garbage means unreferenced objects.

Garbage Collection is process of reclaiming the runtime unused memory automatically. In other
words, it is a way to destroy the unused objects.

To do so, we were using free() function in C language and delete() in C++. But, in java it is performed
automatically. So, java provides better memory management.

Advantage of Garbage Collection

o It makes java memory efficient because garbage collector removes the unreferenced objects
from heap memory.

o It is automatically done by the garbage collector(a part of JVM) so we don't need to make
extra efforts.

1) By nulling a reference:

1. Employee e=new Employee();

2. e=null;

2) By assigning a reference to another:

1. Employee e1=new Employee();

2. Employee e2=new Employee();

3. e1=e2;//now the first object referred by e1 is available for garbage collection

3) By anonymous object:

1. new Employee();
finalize() method

The finalize() method is invoked each time before the object is garbage collected. This method can be
used to perform cleanup processing. This method is defined in Object class as:

1. protected void finalize(){}

Note: The Garbage collector of JVM collects only those objects that are created by new keyword. So
if you have created any object without new, you can use finalize method to perform cleanup
processing (destroying remaining objects).

gc() method

The gc() method is used to invoke the garbage collector to perform cleanup processing. The gc() is
found in System and Runtime classes.

1. public static void gc(){}

Note: Garbage collection is performed by a daemon thread called Garbage Collector(GC). This thread
calls the finalize() method before object is garbage collected.

Synchronization

In Java, synchronization is a technique to control the access of multiple threads to shared resources,
ensuring that only one thread can access a resource at a time. This prevents race conditions, where
multiple threads try to modify or access shared data concurrently, potentially causing unexpected
and incorrect outcomes.

Why Synchronization is Important:

When multiple threads access shared data simultaneously without proper control, they may:

 Interfere with each other’s operations.

 Cause inconsistent or incorrect data processing.

 Lead to unpredictable program behavior.

Imagine a simple bank application where multiple people can withdraw money from the same
account. Let’s say two people, Alice and Bob, both try to withdraw money from the same account at
the same time. Without synchronization, they might both see the same initial balance and proceed
with their withdrawals, leading to an incorrect final balance.

Scenario:

1. Account Balance: Imagine there is an account with a balance of $100.

2. Withdrawals: Alice and Bob both try to withdraw $80 at the same time.

Without Synchronization:

1. Step 1: Both Alice and Bob’s threads access the account at the same time and see the
balance is $100.
2. Step 2: Alice’s thread deducts $80, so she sees the new balance as $20.

3. Step 3: Bob’s thread, without knowing Alice already withdrew, also deducts $80, and he also
sees the new balance as $20.

4. Result: Both withdrawals go through, but the final balance should be -$60, not $20. This is
incorrect because both threads changed the balance at the same time.

Final Outcome:

By synchronizing the withdraw() method, we ensure only one thread accesses the account
balance at a time. This prevents both Alice and Bob from withdrawing at the same time and
ensures the balance is accurate after each transaction

Thread Synchronization

There are two types of thread synchronization mutual exclusive and inter-thread communication.

1. Mutual Exclusive

1. Synchronized method.

2. Synchronized block.

3. Static synchronization.

2. Cooperation (Inter-thread communication in java)

What is Mutual Exclusion?

Mutual exclusion ensures that only one thread can access a critical section (a part of code that
modifies shared resources) at a time. This avoids errors when multiple threads try to access or
modify shared data simultaneously.

Imagine a shared bank account with two people, Alice and Bob, who both try to withdraw money at
the same time:

1. Without Mutual Exclusion: Alice and Bob both see the same initial balance, say $100. They
both withdraw $80 at the same time, so the balance shows $20 for both. This is a mistake
since two withdrawals of $80 should lead to a negative balance, but they both see $20
because they accessed the balance at the same time.

2. With Mutual Exclusion:

o When Alice’s thread starts a withdrawal, it locks access to the balance, so Bob’s
thread waits until Alice finishes.

o Alice withdraws $80, the balance is now $20, and then she releases the lock.

o Now, when Bob’s thread accesses the balance, he sees $20 and realizes he can’t
withdraw $80, so he doesn’t proceed.

In Java, synchronized methods and synchronized blocks are used to enforce mutual exclusion.

What is Inter-Thread Communication?


Inter-thread communication is about making threads wait and notify each other, so they can work
together smoothly. Java uses three key methods for this: wait(), notify(), and notifyAll().

Let’s use a Producer-Consumer example to explain:

Imagine you have a store with limited storage (capacity of 10 items).

 Producer adds items to the store.

 Consumer removes items from the store.

But, they have to cooperate:

 If the store is full, the Producer must wait.

 If the store is empty, the Consumer must wait.

How it Works:

1. The Producer tries to add an item:

o If the store is not full, it adds the item and calls notify() to let the Consumer know an
item is available.

o If the store is full, it calls wait() to pause, so it stops adding items until there’s space.

2. The Consumer tries to remove an item:

o If the store has items, it removes one and calls notify() to let the Producer know
there’s space.

o If the store is empty, it calls wait() to pause until an item is added.

A synchronized method in Java is a method that can only be executed by one thread at a time. It is
used to control access to a shared resource (like a variable or an object) so that only one thread can
access it, preventing conflicts or errors when multiple threads try to access the same resource
simultaneously.

Simple Explanation:

Imagine two people, Alice and Bob, trying to use a printer at the same time. If both are allowed to
access the printer at once, they might interfere with each other (e.g., printing the wrong pages, or
the printer breaking).

 Without synchronization: Both Alice and Bob can print at the same time, causing problems.

 With synchronization: If Alice is using the printer, Bob has to wait until Alice is done. Once
Alice is finished, Bob can use it.

Example:

java

Copy code

class Printer {
// Synchronized method

public synchronized void printDocuments(String document) {

// Simulate printing

System.out.println("Printing: " + document);

try {

Thread.sleep(1000); // Simulating time taken to print

} catch (InterruptedException e) {

e.printStackTrace();

public class Main {

public static void main(String[] args) {

Printer printer = new Printer();

// Creating two threads

Thread thread1 = new Thread(() -> printer.printDocuments("Document 1"));

Thread thread2 = new Thread(() -> printer.printDocuments("Document 2"));

thread1.start();

thread2.start();

Synchronized Block in Java

Synchronized block can be used to perform synchronization on any specific resource of the method.

Suppose we have 50 lines of code in our method, but we want to synchronize only 5 lines, in such
cases, we can use synchronized block.

If we put all the codes of the method in the synchronized block, it will work same as the synchronized
method.

Points to Remember

o Synchronized block is used to lock an object for any shared resource.


o Scope of synchronized block is smaller than the method.

o A Java synchronized block doesn't allow more than one JVM, to provide access control to a
shared resource.

o The system performance may degrade because of the slower working of synchronized
keyword.

o Java synchronized block is more efficient than Java synchronized method.

Static Synchronization

If you make any static method as synchronized, the lock will be on the class not on object.

Without Static Synchronization:

 Imagine you have two objects of a class, say Table. You create two objects, object1 and
object2, and have multiple threads (e.g., t1, t2, t3, t4) trying to access synchronized methods
in these objects.

 If the synchronized method is part of an instance (like a regular method), each object
(object1 and object2) has its own lock. So:

o t1 and t2 can safely work on object1 because they share the same lock for that
object.

o t3 and t4 can safely work on object2 because they share the same lock for that
object.

o However, there's no protection between threads on different objects, meaning t1


(on object1) and t3 (on object2) could interfere with each other because each object
has its own lock.

With Static Synchronization:

 Now, if you make the method static, the lock is placed on the class itself instead of each
individual object.

 So, if multiple threads (e.g., t1, t2, t3, t4) try to access the static synchronized method, they
must share the same lock because it's now the class that holds the lock.
o This means even though t1 is working on object1 and t3 is working on object2, they
can't interfere with each other because they are both trying to acquire the class-
level lock.

o In this case, there’s no chance of interference, because the lock is shared across all
objects of that class.

Summary:

 Without static synchronization, each object gets its own lock, so threads on different objects
can still interfere.

 With static synchronization, all objects share a single lock on the class, preventing
interference even if threads work on different objects.

Deadlock in Java

Deadlock in Java is a part of multithreading. Deadlock can occur in a situation when a thread is
waiting for an object lock, that is acquired by another thread and second thread is waiting for an
object lock that is acquired by first thread. Since, both threads are waiting for each other to release
the lock, the condition is called deadlock.

Inter-Thread Communication in Java

Inter-thread communication is a mechanism that allows threads to communicate with each other
and coordinate their activities. In Java, this is typically achieved using the methods provided by the
Object class: wait(), notify(), and notifyAll(). These methods enable threads to signal each other to
proceed or wait, facilitating cooperation between threads.

Key Concepts:

1. Wait: A thread can pause its execution by calling the wait() method on an object. The thread
will remain in a waiting state until it is notified by another thread.

2. Notify: A thread can wake up one of the waiting threads by calling the notify() method on an
object.

3. NotifyAll: A thread can wake up all the waiting threads by calling the notifyAll() method on
an object.

Example: Producer-Consumer Problem

The Producer-Consumer problem is a classic example of inter-thread communication, where one


thread produces data and another thread consumes it. The producer thread can only produce if
there is space in the buffer, and the consumer thread can only consume if there is data in the buffer.
In this example:

 Producer adds items to the buffer.

 Consumer removes items from the buffer.

 Both threads must coordinate to avoid issues like overproducing or consuming from an
empty buffer.

Test.java

1. class Customer{

2. int amount=10000;

3.

4. synchronized void withdraw(int amount){

5. System.out.println("going to withdraw...");

6.

7. if(this.amount<amount){

8. System.out.println("Less balance; waiting for deposit...");

9. try{wait();}catch(Exception e){}

10. }

11. this.amount-=amount;

12. System.out.println("withdraw completed...");

13. }

14.

15. synchronized void deposit(int amount){

16. System.out.println("going to deposit...");

17. this.amount+=amount;

18. System.out.println("deposit completed... ");

19. notify();

20. }

21. }

22.

23. class Test{

24. public static void main(String args[]){

25. final Customer c=new Customer();


26. new Thread(){

27. public void run(){c.withdraw(15000);}

28. }.start();

29. new Thread(){

30. public void run(){c.deposit(10000);}

31. }.start();

32.

33. }}

Output:

going to withdraw...

Less balance; waiting for deposit...

going to deposit...

deposit completed...

withdraw completed

Interrupting a Thread:

If any thread is in sleeping or waiting state (i.e. sleep() or wait() is invoked), calling the interrupt()
method on the thread, breaks out the sleeping or waiting state throwing InterruptedException. If the
thread is not in the sleeping or waiting state, calling the interrupt() method performs normal
behaviour and doesn't interrupt the thread but sets the interrupt flag to true.

 interrupt(): Used to interrupt a specific thread, setting its interrupt flag to true. If the thread is
blocked, it will throw InterruptedException.

 interrupted(): A static method that checks and clears the interrupt status of the current thread.

 isInterrupted(): Checks the interrupt status of the thread on which it is called, without clearing the
interrupt flag.

You might also like