Understanding java.lang.Thread.State: wait(parking)

1. Overview

In this article, we will discuss Java thread status – specifically, thread.state.wait, We will look at the ways in which a thread enters this state and see the differences between them. Finally, we’ll take a closer look at lock support class, which provides several static utility methods for synchronization.

2. Admission thread.state.wait

Provides multiple ways to cast threads in Java To Wait State.

2.1. Object.weight()

One of the most standard ways we can put a thread To Wait is through the state Wait() way. When a thread owns an object’s monitor, we can pause its execution until another thread has completed some work and wake it up using please inform() method, While execution is paused, the thread is in wait (on object monitor) The state, which is also reported in the program’s thread dump:

"WAITING-THREAD" #11 prio=5 os_prio=0 tid=0x000000001d6ff800 nid=0x544 in Object.wait() [0x000000001de4f000]
   java.lang.Thread.State: WAITING (on object monitor)

2.2. thread.join()

Another method we can use to stop the execution of a thread is Add() Call. When our main thread needs to wait for the first worker thread to finish, we can call Add() from main thread to worker thread instance, Execution will be stopped and will enter main thread To Wait State, reported from justack as wait (on object monitor),

"MAIN-THREAD" #12 prio=5 os_prio=0 tid=0x000000001da4f000 nid=0x25f4 in Object.wait() [0x000000001e28e000]
   java.lang.Thread.State: WAITING (on object monitor)

2.3. lock support.park()

Finally, we can also set up a thread To Wait state with park() static method of lock support Class. calling park() will stop execution for the current thread and put it in To Wait State – and more specifically, waiting (parking) State In form of justack The report will show:

"PARKED-THREAD" #11 prio=5 os_prio=0 tid=0x000000001e226800 nid=0x43cc waiting on condition [0x000000001e95f000]
   java.lang.Thread.State: WAITING (parking)

Since we want to better understand thread parking and unparking, let’s take a closer look at how it works.

3. Parking and Unparking Thread

As we saw earlier, we can park and unpark threads using the features provided by threads lock support Class. this is a wrapper of the class vulnerable class, and most of its methods immediately delegate to it. However, since vulnerable is considered an internal Java API and should not be used, lock support The official way we can access parking utilities,

3.1. how to use lock support

using the lock support is straight. If we want to stop the execution of a thread, we call park() way. We don’t need to provide a reference to the Thread object – the code aborts the thread that calls it.

Let’s look at a simple parking example:

public class Application {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            int acc = 0;
            for (int i = 1; i <= 100; i++) {
                acc += i;
            }
            System.out.println("Work finished");
            LockSupport.park();
            System.out.println(acc);
        });
        t.setName("PARK-THREAD");
        t.start();
    }
}

We have created a minimal console application that collects numbers from 1 to 100 and prints them. If we run this, we will see that it prints work finished But no result. That’s for sure because we say park() right before.

Let it go park-thread finish, we have to unpark it, To do this, we have to use a separate thread. we can use Main thread (thread running Main() method) or create a new one.

For simplicity, let’s use Main thread:

t.setName("PARK-THREAD");
t.start();
Thread.sleep(1000);
LockSupport.unpark

we add a sec sleep to it Main thread to go park-thread Finish accumulating and park yourself. After that, we unpark it by calling unpark (thread), As expected, during unparking, we need to reference the thread object we want to start.

With our changes, the program now terminates and prints the result properly, 5050,

3.2. unpark permit

The interiors of the Parking API work using permits. This, in practice, works like a single permit. Sikandra, Park Permit is used to manage the state of the thread internally park() method of consuming it, while unpark() makes available.

Since we can have only one permit available per thread, which can be called unpark() Sometimes the method has no effect. even one park() The call will disable the thread.

However, what is interesting is that the parked thread waits for a permit to become available to re-enable itself. If the permit is already available when calling park()So the thread is never disabled. the permit is used, park() The call returns immediately, and the thread continues execution.

We can see this effect by removing the call Sleep() In the previous code snippet:

//Thread.sleep(1000);
LockSupport.unpark

If we run our program again, we will see that there is no delay park-thread execution. that's because we say unpark() immediately, which provides for the permit park(),

3.3. park overload

lock support class is included park (object blocker) overload method. blocker The logic is the synchronization object which is responsible for thread parking. The object we provide doesn't affect that parking process, but it is reported in the thread dump, which can help us diagnose concurrency issues.

Let's change our code to include the Synchronizer object:

Object syncObj = new Object();
LockSupport.park(syncObj);

If we remove the call unpark() and run the application again, it will hang. if we use justack what to see park-thread doing, we will get:

"PARK-THREAD" #11 prio=5 os_prio=0 tid=0x000000001e401000 nid=0xfb0 waiting on condition [0x000000001eb4f000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x000000076b4a8690> (a java.lang.Object)

As we can see, which item is in the last line park-thread waiting for. This is helpful for debugging purposes, so we should like park (object) Overload.

4. Parking vs. Waiting

Since both these APIs provide us with similar functionality, which one should we prefer? en general, lock support The class and its features are considered low-level APIs. Additionally, the API can be easily abused, leading to unexplained deadlocks. For most cases, we should use thread of class Wait() And Add(),

The advantage of using parking is that we do not need to enter synchronized Block to disable the thread. it is important because synchronized Happens in the block code-before relationship is established, which forces all variables to be refreshed and can potentially lead to low performance if it is not needed. However, this optimization should rarely come into play.

5. Epilogue

In this article, we explored lock support Class and its Parking API. We saw how we can use it to deactivate threads and explained how it works internally. Finally, we compared it with the more common wait() / join() APIs and their differences demonstrated.

As always, code examples can be found on GitHub.

       

Leave a Comment