Java Suspended Thread States
Java threads can be in six different states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED. We will explore them here.
Join the DZone community and get the full member experience.
Join For FreeJava threads can be in six different states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED. When a thread is suspended (i.e., unable to progress further), it will be one of these three suspended thread states: BLOCKED, WAITING, TIMED_WAITING. Let’s discuss these three states with real-life fun examples
BLOCKED
A thread enters the ‘BLOCKED’ state when it’s trying to access a resource that’s currently held by another thread. In this state, the blocked thread cannot proceed until the resource it needs becomes available.
When Will a Thread Enter Into a BLOCKED State?
A thread will enter into a ‘BLOCKED’ state in one of the following scenarios:
1. Synchronized method: Threads enter the ‘BLOCKED’ state when they contend for access to the synchronized method. Let’s consider this sample code:
public synchronized void getData() {
: :
}
Here, the getData()
method is defined as a ‘synchronized’ method. When a method is marked with a synchronized
keyword, JVM will allow only one thread to enter into that ‘synchronized’ method at any given time. If any other tries to invoke this ‘synchronized’ method when some other is already executing this method, it will be put into the ‘BLOCKED’ state. If this synchronized method happens to be in a critical code path, then there is a high possibility for multiple threads to enter into this ‘BLOCKED’ state. In general, it’s a good practice to avoid synchronized methods as much as possible for better performance.
2. Synchronized block: When multiple threads contend for access to a synchronized block, only one thread can execute the block at a time. If a thread tries to enter a synchronized block that is already locked by another thread, it goes into the ‘BLOCKED’ state and waits for the lock to be released.
synchronized (sharedLock) {
// Critical section
}
3. ReentrantLock
: If a thread attempts to acquire a ReentrantLock
that is already held by another thread, it will not immediately get the lock. Instead, it will go into the ‘BLOCKED’ state and wait until the lock becomes available. Once the lock is released by the owning thread (the thread that currently holds the lock), one of the blocked threads will be chosen to acquire the lock and transition from the ‘BLOCKED’ state to the ‘RUNNABLE’ state. The thread that successfully acquires the lock will proceed to execute the locked critical section.
ReentrantLock lock = new ReentrantLock();
lock.lock(); // Acquires the lock
// ...
lock.unlock(); // Releases the lock
How To Diagnose BLOCKED State Threads
When threads enter the ‘BLOCKED’ state, it’s essential to identify the specific lines of code or methods causing this behavior. To diagnose such issues non-intrusively, the recommended approach is thread dump analysis. Tools like fastThread and yCrash are invaluable for this purpose. yCrash provides an insightful transitive dependency graph of ‘BLOCKED’ threads, aiding in understanding the thread contention. The graph displays the following key information:
Blocked threads: Threads currently in the ‘BLOCKED’ state.
Blocking thread: Culprit Thread that caused the other threads to enter into the ‘BLOCKED’ state.
Stack traces: Stack trace of both the blocking thread and the ‘BLOCKED’ thread.
Fig: Transitive dependency graph showing BLOCKED threads generated by yCrash
By utilizing these tools and techniques, you can gain insights into the root causes of thread contention and “BLOCKED” states, enabling you to optimize your application’s performance and concurrency.
Real-Life Example
Say, today, you are going for a job interview. This is your dream job, which you have been targeting for the last few years. You wake up early in the morning, get ready, put on your best outfit, and look sharp in front of the mirror. Now, you step out to your garage and realize that your wife has already taken the car. In this scenario, you only have one car, so what will happen? In real life, a fight may happen :-). Here you are ‘BLOCKED’ because your wife has already taken the car. You won’t be able to go to the interview.
This is the ‘BLOCKED’ state. Explaining it in technical terms, you are the thread T1, your wife is the thread T2, and the lock is the car. T1 is ‘BLOCKED’ on the lock (i.e., the car) because T2 has already acquired this lock.
WAITING
A thread enters the ‘WAITING’ state when it’s waiting for a specific condition to be satisfied, such as a signal from another thread. Threads in the ‘WAITING’ state don’t consume CPU resources and remain inactive until they are explicitly awakened by another thread.
When Will a Thread Enter Into a WAITING State?
A Thread will enter into a ‘WAITING’ state when it’s calling one of the following methods:
1. Object#wait()
with no timeout: A thread enters the ‘WAITING’ state when it calls the wait()
method on an object. This method is typically used for synchronization and coordination between threads. The thread will remain in the ‘WAITING’ state until another thread calls the notify()
or notifyAll()
method on the same object.
2. Thread#join()
with no timeout: Thread.join()
method in Java is employed to make a calling thread wait until another specified thread finishes its execution. When a thread invokes join()
on a target thread, the caller enters a ‘WAITING’ state until the target thread completes its task. This mechanism is useful for coordinating the execution of multiple threads, ensuring that a particular thread’s work is finished before proceeding with subsequent operations. Once the target thread finishes executing, the calling thread transitions back to its normal state and continues its own execution. This synchronization approach is valuable in scenarios where you need to manage the order or dependencies of thread execution.
3. LockSupport.park()
: Invoking LockSupport.park()
in Java induces a thread to transition into the ‘WAITING’ state. This method provides a fine-grained synchronization mechanism where a thread voluntarily relinquishes its CPU time and remains in a waiting state until it receives an explicit signal to continue, typically through the unpark()
method. This approach is often utilized in more complex concurrency scenarios to intricately coordinate thread activities, enabling threads to synchronize and communicate with precision according to the needs of the application.
4. CyclicBarrier.await()
: Threads waiting at a CyclicBarrier
using the await()
method enter the ‘WAITING’ state until the required number of threads arrive.
5. CountDownLatch.await()
: Threads waiting on a CountDownLatch
using the await()
method enter the “WAITING” state until the latch’s count reaches zero.
Real-Life Example
Let’s say a few minutes later, your wife comes back home with the car. Now you realize that the interview time is approaching, and there is a long distance to drive to get there. So, you put all the power on the gas pedal in the car. You drive at 100 mph when the allowed speed limit is only 60 mph. Your luck: A traffic cop sees you driving over the speed limit, and he pulls you over to the curb. Now you are entering into the WAITING state, my friend. You stop driving the car and sit idly in the car until the cop investigates you and then lets you go. Basically, until he lets you go, you are stuck in the WAITING state.
Explaining it in technical terms, you are thread T1, and the cop is thread T2. You released your lock (i.e., you stopped driving the car) and went into the WAITING state. Until the cop (i.e., T2) lets you go, you will be stuck in this WAITING state.
TIMED_WAITING
Threads enter the TIMED_WAITING state when they are waiting for a specific amount of time. This state is often used when a thread needs to wait for a resource but doesn’t want to wait indefinitely. After the specified time elapses, the thread can either proceed if the resource is available or transition to another state.
When Will a Thread Enter Into a TIMED_WAITING State?
Here’s a list of methods in Java that can cause a thread to enter the ‘TIMED_WAITING’ state:
1. Thread.sleep
(long millis): Pauses the current thread’s execution for a specified duration of time.
2. Object.wait
(long timeout): Makes a thread wait for a specified duration or until another thread calls notify()
or notifyAll()
on the same object, whichever comes first.
3. LockSupport.parkNanos
(long nanos): Similar to LockSupport.park()
, but allows you to specify a time in nanoseconds for the thread to be parked.
4. LockSupport.parkUntil
(long deadline): Parks the current thread until a given deadline, specified in milliseconds since the epoch.
5. Condition.await
(long time, TimeUnit unit): Used with the java.util.concurrent.locks.Condition interface
to wait for a condition to be met with a specified timeout.
6. Thread.join
(long millis): Waits for a thread to finish execution for a specified duration of time.
It’s important to note that the “TIMED_WAITING” state indicates that a thread is waiting for a specified amount of time before it can continue its execution.
Real-Life Example
Despite all the drama, you did extremely well in the interview, impressed everyone, and got this high-paying job. (Congratulations!) You come back home and tell your neighbor about this new job and how excited you are about it. Your friend says that he is also working in the same office building. He suggests that the two of you should drive together. You think it’s a great idea. So on the first day of work, you go to his house. You stop your car in front of his house. You wait for 10 minutes, but your neighbor still doesn’t come out. You go ahead and start driving to work, as you don’t want to be delayed on your first day. Now, this is TIMED_WAITING.
Explaining it in technical terms, you are thread T1, and your neighbor is thread T2. You release the lock (i.e., stop driving the car) and wait up to 10 minutes. If your neighbor, T2, doesn’t come out in 10 minutes, you start driving the car again.
Video
This five-minute video covers the BLOCKED, WAITING, and TIMED_WAITING thread states all through the illustrative example of a job interview that we have discussed in this post.
Conclusion
In the realm of Java threading, the states of BLOCKED, WAITING, and TIMED_WAITING emerge as intriguing suspensions where threads momentarily pause their journey. By paralleling these states with real-life scenarios, we’ve uncovered their essence: exclusive resource access, patient anticipation, and timed pauses. Understanding these states empowers us to construct efficient multithreaded applications. Just as life’s moments of waiting lead to progress, these states guide threads to execution’s completion. As you navigate the dynamic landscape of programming, remember these states’ significance and thread confidently toward concurrency mastery.
Published at DZone with permission of Ram Lakshmanan, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments