Defining Threads:
A thread serves as the smallest executable unit within a process. It operates along its distinct execution path within a given process. Multiple threads can coexist within a single process.
Grasping Multithreaded Programming:
In the realm of programming or applications, the term "multithreaded programming" denotes the scenario where two or more threads execute their designated tasks concurrently. Java constitutes a supportive environment for crafting multithreaded programs.
Diverse Thread Categories:
Java encapsulates two distinct thread categories:
User Threads:
User threads emerge through the initiation of applications or users. They hold elevated priority levels and contribute to the non-termination of the JVM until their execution concludes. The JVM remains in a waiting state, anticipating the fulfillment of user thread tasks. These threads function as foreground threads, serving a visible role in the program's operation.
Daemon Threads:
Daemon threads predominantly arise from the JVM's internal workings. They consistently operate in the background, orchestrating tasks such as garbage collection. Displaying lower priority, daemon threads don't command the JVM's waiting period. The JVM enters its closure phase once user threads wrap up their tasks, irrespective of daemon threads' status.
Creating Threads in Java:
Java offers two distinct methods for creating threads.
Extending the java.lang.Thread Class:
java
class MyThread extends Thread {
@Override
public void run() {
// Define the task to be executed here
}
}
MyThread myThread = new MyThread(); // Instance of MyThread created
myThread.start(); // Commence execution of myThread
Implementing the java.lang.Runnable Interface:
java
class MyRunnable implements Runnable {
@Override
public void run() {
// Specify the task to be performed here
}
}
Thread t = new Thread(new MyRunnable()); // Thread created using Runnable
t.start(); // Initiate the thread's execution
These approaches enable the establishment of threads in Java, granting you the flexibility to manage concurrent tasks efficiently.
Thread Priority Levels:
In Java, threads can be assigned distinct priority levels, facilitating task management and execution. There are three priority constants:
MIN_PRIORITY: This sets the lowest attainable priority, represented by the value 1.
NORM_PRIORITY: Representing the standard priority, this is assigned a value of 5.
MAX_PRIORITY: This denotes the highest achievable priority, indicated by the value 10.
By default, a thread inherits its priority from its parent thread. However, priority can be adjusted dynamically using the setPriority() method.
Synchronizing Threads:
Synchronization ensures threads execute specific methods or blocks sequentially rather than simultaneously. Java employs the synchronized keyword to achieve synchronization.
When a method or block is synchronized, only one thread can enter at a time. Concurrent threads that intend to access the synchronized method or block must wait until the preceding thread completes. This mechanism prevents interference and fosters thread safety.
Synchronization hinges on the concept of an "object lock" or "monitor," which can be summarized as follows:
An object lock is created when an object is instantiated from a class.
Each object possesses a solitary object lock.
Threads vying for access to synchronized methods must obtain the object lock associated with that instance, releasing it once execution concludes.
Concurrent threads seeking entry into synchronized methods must await the release of the object lock.
For static synchronized methods, threads require the class lock, as static members reside within the class memory.
Addressing Deadlock:
Deadlock arises when multiple threads remain blocked indefinitely, each awaiting the release of resources (locks) held by others. Lock ordering and lock timeout are strategies to avert deadlock:
Lock Ordering: Threads follow a predetermined order to acquire required locks, preventing circular dependencies. This approach circumvents deadlock.
Lock Timeout: Threads are assigned a time frame to obtain locks; failing to do so prompts a retry after a certain interval.
Inter-Thread Communication:
Java threads communicate via the wait(), notify(), and notifyAll() methods:
wait(): The executing thread relinquishes the object's lock, awaiting notification from another thread via notify() or notifyAll().
notify(): One waiting thread is awakened randomly after invoking wait() on an object.
notifyAll(): All threads waiting on the object through wait() are roused. However, only one thread acquires the lock based on priority.
Thread Lifecycle and States:
A thread's existence can be described by six states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED.
NEW: Precedes the invocation of start() method.
RUNNABLE: Follows the start() method call, indicating execution readiness.
BLOCKED: Evident during synchronization when a thread awaits an object lock or in deadlock scenarios.
WAITING: Characterizes threads paused by wait() or join() methods.
TIMED_WAITING: Applies to threads in sleep(), wait() with a timeout, or join() with a timeout.
TERMINATED: Marks a thread's conclusion post-execution.
Comments