Unit Iv - Java
Unit Iv - Java
Thread can be referred to as a lightweight process. Thread uses fewer resources to create and
exist in the process; thread shares process resources. The main thread of Java is the thread that is
started when the program starts. The slave thread is created as a result of the main thread. This is
the last thread to complete the execution.
You can create threads by implementing the runnable interface and overriding the run() method.
Then, you can create a thread object and call the start() method.
@Override
System.out.println("Thread running");
thread.start();
@Override
System.out.println("Thread running");
thread.start();
Key Points:
start() vs run(): The start() method creates a new thread and executes the run() method in
that new thread. Calling run() directly executes the code within the current thread.
Thread Lifecycle: Threads go through several states, including new, runnable, running,
blocked/waiting, and terminated.
Main Thread: Every Java program has a main thread that starts execution.
Multithreading: Java supports multithreading, enabling concurrent execution of different parts
of a program.
Thread Priorities: Threads can have priorities (1-10), influencing their scheduling.
Concurrency Issues: Sharing resources between threads can cause issues. Synchronization
mechanisms may be required.
Stopping a Thread
Volatile Flag:
A common way to stop a thread is by using a volatile boolean flag. The thread checks this flag in its
loop and exits when the flag is set to true. Volatile ensures that changes to this flag are visible
across threads.
Interrupt Method:
The interrupt() method sets an interrupt flag on the thread. If the thread is in a blocking state (e.g.,
sleeping or waiting), it throws an InterruptedException. Otherwise, the thread can check its interrupt
status using Thread.currentThread().isInterrupted() and exit gracefully.
ExecutorService:
When using thread pools, shutdown() and shutdownNow() methods of ExecutorService are used to
stop threads. shutdown() allows the threads to finish their current tasks,
while shutdownNow() attempts to stop all actively executing tasks.
Blocking a Thread
Synchronized Blocks:
When a thread encounters a synchronized block or method, it attempts to acquire a lock on the
object associated with the synchronized block/method. If the lock is held by another thread, the
thread goes into the BLOCKED state and waits until the lock is released.
Wait/Notify:
Threads can also be blocked using wait(), wait(long), or wait(long, int) methods of the Object
class. These methods cause the thread to release the lock on the object and wait until notified by
another thread using notify() or notifyAll().
Sleep Method:
The sleep(long) method pauses the execution of the current thread for a specified time.
Join Method:
The join() method causes one thread to wait for another thread to complete.
The life cycle of a thread in Java involves several stages, each representing a different state of
execution. These states are defined by the Thread.State enum and include:
New:
This is the initial state when a thread object is created using the new keyword, but it has not yet
started execution. At this stage, the thread is not alive.
Runnable:
After calling the start() method on the thread object, it enters the Runnable state. In this state, the
thread is eligible to run and is waiting for its turn to be scheduled by the thread scheduler.
Running:
The thread scheduler selects a thread from the runnable pool and assigns it to the CPU for
execution. During this state, the thread's code is actively being executed.
Blocked/Waiting:
A thread may enter the blocked or waiting state when it is waiting for some external event to
occur. This can include:
Waiting for a monitor lock to enter a synchronized block or method.
Waiting for another thread to complete a specific action indefinitely.
Waiting for I/O resources to become available.
Timed Waiting:
Similar to the waiting state, but the thread waits for a specific period. This occurs when the thread
uses methods like sleep() or wait() with a timeout.
Terminated:
This is the final state of a thread when its execution is completed. A thread may terminate naturally
by exiting the run() method or due to an exception. Once terminated, a thread cannot be restarted.
The thread scheduler is responsible for managing the transition of threads between the Runnable and
Running states. The thread's priority can influence how often it gets scheduled, with higher priorities
having a greater chance of being selected.
Threads can be created by: Extending the Thread class and Implementing the Runnable interface.
Understanding the thread life cycle is important for managing concurrency and ensuring efficient
multithreaded applications in Java.
Thread Exception
// Importing Classes/Files
import java.io.*;
System.out.println("Thread is running");
try {
catch (Exception e) {
// Exception handler
System.out.println(
Output:
Another thread is not supported
2. Exception handling with sleep method(): sleep() method of thread class is used where there is
a demand to sleep the thread for a particular period of time for the proper workflow of the code.
Syntax:
public static void sleep(long milliseconds) ; // generally used
public static void sleep(long milliseconds, int nanoseconds) ; // used to illustrate the precision
only
System.out.println("Thread 1 running");
});
System.out.println("Thread 2 running");
});
thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
thread1.start();
thread2.start();
Thread synchronization in Java is a mechanism that controls the access of multiple threads to shared
resources, ensuring that only one thread can access a critical section of code at a time, preventing
data inconsistency and race conditions. It is essential in multithreaded environments to prevent
thread interference and maintain data integrity.
Here's how synchronization works in Java:
1. Synchronized Keyword:
The synchronized keyword is the primary way to achieve synchronization in Java.
It can be applied to methods or blocks of code.
When a thread enters a synchronized method or block, it acquires a lock on the object associated
with that method or block.
Only one thread can hold the lock at a time, ensuring exclusive access to the synchronized code.
Other threads attempting to enter the synchronized section will be blocked until the lock is
released.
2. Synchronized Methods:
When a method is declared as synchronized, the entire method is protected by the lock
associated with the object on which the method is called.
Only one thread can execute a synchronized method of an object at a time.
3. Synchronized Blocks:
Synchronized blocks allow you to synchronize only a specific portion of code, rather than the
entire method.
They use a lock object, which can be any object, to control access to the synchronized section.
The syntax is synchronized(lockObject) { /* synchronized code */ }.
4. Implicit Locks:
Every object in Java has an associated implicit lock, also called a monitor.
When a thread enters a synchronized method or block, it acquires this implicit lock.
The lock is automatically released when the thread exits the synchronized section, whether
normally or due to an exception.
5. Importance of Synchronization:
Prevents race conditions: Ensures that shared resources are accessed and modified by only one
thread at a time, avoiding unpredictable outcomes.
Maintains data consistency: Prevents data corruption that can occur when multiple threads access
and modify shared data concurrently.
Ensures thread safety: Makes code safe for use in a multithreaded environment.
6. Challenges of Synchronization:
Performance overhead: Synchronization can introduce performance overhead due to the locking
and blocking of threads.
Deadlocks: Improper use of synchronization can lead to deadlocks, where threads are blocked
indefinitely waiting for each other to release locks.