Multithreading in Java
Multithreading in Java
● A thread is a lightweight process that can run concurrently with other threads.
● It is the smallest unit of a program that can be executed independently.
Example Program:
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running...");
}
try {
System.out.println("Thread is running...");
Thread.sleep(1000); // Timed Waiting state
} catch (InterruptedException e) {
System.out.println("Thread interrupted.");
t1.start();
try {
Thread.sleep(500);
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Key Methods in Thread Class
Main Thread
Every application has at least one thread, known as the main thread. When a Java
program starts, the Java Virtual Machine (JVM) creates this main thread, which is
responsible for the execution of the main method. From this main thread, additional
threads can be spawned to perform parallel processing.
class MainThreadExample {
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
try {
Explanation
The main thread and normal threads (also known as user-defined threads) have
some key differences.
Main Thread
1. Creation:
○ Automatically created by the JVM when the program starts.
○ Executes the main method of the class.
2. Entry Point:
○ The starting point of any Java application.
○ Responsible for the initial setup and starting other threads if necessary.
3. Lifecycle:
○ Starts when the program begins.
○ Usually the last thread to complete, ensuring all user-defined threads
have finished their execution before the program terminates.
4. Control:
○ Can create, start, and control the lifecycle of other threads.
○ Often acts as a coordinator, managing other threads and resources.
5. Termination:
○ The JVM waits for the main thread to complete before terminating the
program, provided all other non-daemon threads have finished.
1. Creation:
○ Created explicitly by the programmer using the Thread class or by
implementing the Runnable interface.
○ Can be started from the main thread or from other user-defined
threads.
2. Entry Point:
○ The starting point is defined by the run method of the Thread class or
Runnable interface.
3. Lifecycle:
○ Starts when the start method is called.
○ Independently runs and completes its task.
○ Its lifecycle is managed by the thread that created it or by the
programmer.
4. Control:
○ Can be controlled and coordinated by other threads, including the main
thread.
○ Can perform various tasks concurrently with other threads.
5. Termination:
○ Can terminate when its run method completes, when it is interrupted,
or when it explicitly calls methods to stop itself.
Step-by-Step Code
1. Define a Thread Class: Extend the Thread class and override the run
method.
2. Create and Start Threads: In the main method, create instances of the thread
class and start them.
MyThread(String threadName) {
this.threadName = threadName;
@Override
try {
} catch (InterruptedException e) {
}
// Main class to run the threads
thread1.start();
thread2.start();
Explanation
1. MyThread Class:
○ This class extends the Thread class.
○ It has a constructor to set the thread name.
○ The run method contains a loop that prints the thread name and
iteration number, then sleeps for 0.5 seconds.
2. Main Method:
○ In the main method, we create two instances of the MyThread class,
each with a different name.
○ We start both threads using the start method, which internally calls
the run method.
Thread priorities:
They are used to hint the thread scheduler about the relative importance of threads.
The scheduler uses these priorities to decide when each thread should run. Here
,each thread is assigned a priority, which is an integer value between
Thread.MIN_PRIORITY (1) and Thread.MAX_PRIORITY (10). By default, a
thread is given a priority of Thread.NORM_PRIORITY (5).
1. Range of Priorities:
○ Thread.MIN_PRIORITY = 1
○ Thread.NORM_PRIORITY = 5
○ Thread.MAX_PRIORITY = 10
2. Setting Thread Priorities:
○ You can set a thread's priority using the setPriority(int
priority) method.
○ You can get a thread's priority using the getPriority() method.
3. Priority Inheritance:
○ When a new thread is created, it inherits the priority of the thread that
created it.
4. Scheduler Behavior:
○ The behavior of thread scheduling is platform-dependent. On some
platforms, higher-priority threads may run more frequently than
lower-priority threads.
○ Java does not guarantee the exact behavior of thread priorities. It is up
to the JVM implementation and the underlying operating system.
Example Programs :
MyThread(String threadName) {
this.threadName = threadName;
@Override
try {
} catch (InterruptedException e) {
}
// Main class to run the threads
thread1.setPriority(Thread.MIN_PRIORITY); // Priority 1
thread2.setPriority(Thread.NORM_PRIORITY); // Priority 5
thread3.setPriority(Thread.MAX_PRIORITY); // Priority 10
thread1.start();
thread2.start();
thread3.start();
}
Synchronization In Thread
Synchronized Methods:
● You can use the synchronized keyword to ensure that only one thread can
execute a method at a time.
Example:
public synchronized void synchronizedMethod() {
// code to be synchronized
}
Synchronized Blocks:
● You can use synchronized blocks to lock a specific object instead of locking
the whole method.
Example:
public void method() {
synchronized(this) {
// code to be synchronized
}
}
Intrinsic Locks (or Monitors):
● Every object in Java has an intrinsic lock. A thread automatically acquires the
intrinsic lock when it enters a synchronized method or block, and releases it
when it exits.
Static Synchronization:
Example Program :
// Shared Resource
class Counter {
private int count = 0;
CounterThread(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
Explanation :
Counter Class:
CounterThread Class:
● This class extends the Thread class and increments the counter 1000 times
in the run method.
SynchronizationExample Class:
Key Concepts
1. wait():
○ Causes the current thread to wait until another thread invokes
notify() or notifyAll() on the same object.
○ The current thread must own the object's monitor to call this method
(i.e., it must be in a synchronized block/method).
2. notify():
○ Wakes up a single thread that is waiting on the object's monitor. If
multiple threads are waiting, one is chosen arbitrarily.
○ The current thread must own the object's monitor to call this method.
3. notifyAll():
● Wakes up all threads that are waiting on the object's monitor.
● The current thread must own the object's monitor to call this method.
Suspending Threads
Resuming Threads
● The resume() method was used to resume a thread that had been
suspended.
● It is deprecated because it can cause deadlocks and other synchronization
issues.
Modern Approach: As shown in the example above, use a flag to control when the
thread should resume.
Stopping Threads