“This is the 19th day of my participation in the First Challenge 2022, for more details: First Challenge 2022”.

English document address: www.apiref.com/java11-zh/j…

What is LockSupport?

(Wait/Notify)

Core approach:

Park () and unpark() in LockSupport block and unblock threads, respectively

The way threads wake up and wait

Three ways to make a thread wait and wake up

Method 1: Use the wait() method of Object to make the thread wait, and use the notify() method of Object to wake up the thread.

Option 2: Use the await() method of Condition in the JUC package to make the thread wait, and use the signal() method to wake it up.

Method 3: The LockSupport class can block the current thread and wake up the specified blocked thread.

Method 1: The wait and notify methods of the Object class are used to wait and wake up threads

Test code:

public class LockSupportDemo {

    static Object objectLock = new Object();

    public static void main(String[] args) {
        // 1. Wait and notify must be synchronized
        new Thread(() -> {
            // Only the current wait thread can be awakened
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (objectLock) {
                System.out.println(Thread.currentThread().getName() + "\t =======> Enter lock");
                try {
                    objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t =======> Awakened"); }},"A").start();

        new Thread(() -> {
            synchronized (objectLock) {
                objectLock.notify();
                System.out.println(Thread.currentThread().getName() + "\t =======> Initiate notification"); }},"B").start(); }}Copy the code

Conclusion:

1. Wait and notify must be used together with synchronized otherwise exceptions will be thrown

Conclusion: The methods of wait, notify, and notifyAll in Object must be executed inside synchronized.


2, need to block and wake up

/** ** If the t1 thread waits for 3 seconds, the T2 thread wakes up the T1 thread to continue working. ** If the T1 thread notifies the wait method, the T2 thread will wait for 3 seconds. * Wait, notify, and notifyAll to wake up threads. Otherwise, threads cannot be woken up
public class LockSupportDemo {

    static Object objectLock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            // Only the current wait thread can be awakened
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (objectLock) {
                System.out.println(Thread.currentThread().getName() + "\t =======> Enter lock");
                try {
                    objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t =======> Awakened"); }},"A").start();

        new Thread(() -> {
            synchronized (objectLock) {
                objectLock.notify();
                System.out.println(Thread.currentThread().getName() + "\t =======> Initiate notification"); }},"B").start(); }}Copy the code

Mode 2: The singNAL method after await in Condition interface implements wait and wake up of thread

Test code:

public class LockSupportConditionDemo {

    static Lock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();

    public static void main(String[] args) {
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t ====== enter lock");
                condition.await();
                System.out.println(Thread.currentThread().getName() + "\t ====== awakened");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally{ lock.unlock(); }},"A").start();

        new Thread(() -> {
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "\t ====== notice");
            } finally{ lock.unlock(); }},"B").start(); }}Copy the code

Conclusion:

1. Condition needs to be used with Lock.

2, need to block and wake up

Note: Mode 3 is explained separately later

Traditional synchronized and Lock implement the wait for wake notification constraint

1. A thread needs to acquire and hold a lock first, which must be synchronized or lock

2. The thread must wait and wake up before it can be woken up

Park waits and unpark wakes in the LockSupport class

What is?

Block and wake up the thread by violating the park() and unpark() laws

The LockSupport class uses a concept called Permit to block and wake up threads. Each thread has a Permit.

Permit has two ones and zeros. The default is 0.

Licenses can be described as a (0,1) Semaphore, but unlike Semaphore, licenses have a cumulative upper limit of 1.

Major methods

Core approach:

Core method Park ()/ Park (Object Blocker)

Block the current thread/block the specific thread passed in

public static void park(a) {
    UNSAFE.park(false.0L);
}
Copy the code

Permit defaults to 0, so calling the park() method at first blocks the current thread, wakes up until another thread sets permit to 1, and sets permit to 0 again and returns.

Unpark (Thread Thread)

Wakes up the specified thread in the blocked state

public static void unpark(Thread thread) {
    if(thread ! =null)
        UNSAFE.unpark(thread);
}
Copy the code

Code practice

Thread a = new Thread(() -> {
    System.out.println(Thread.currentThread().getName() + "\t ======= enter lock");
    LockSupport.park();
    System.out.println(Thread.currentThread().getName() + "\t ======== awakened");
}, "A");
a.start();

TimeUnit.SECONDS.sleep(3);

Thread b = new Thread(() -> {
    LockSupport.unpark(a);
    System.out.println(Thread.currentThread().getName() + "\t ======== informed");
}, "A");
b.start();
Copy the code

Test conclusions:

1, support the case of no lock call, the implementation of thread blocking;

2. Support unpark first, and then the park operation is still valid.

Emphasizes the

LockSupport is a basic thread-blocking primitive for creating locks and other synchronization classes.

LockSupport is a thread blocking utility class, all methods are static methods, can let the thread block at any position, after the block also has the corresponding wake up method.

Ultimately, LockSupport calls Unsafe’s native code

LockSupport provides the park() and unpark() methods for blocking and unblocking threads.

LockSupport has a permit associated with each thread that uses it. Permit equal to 1, 0 switch, default is 0,

Calling unpark once increments 1 to become 1.

A call to park consumes permit, which turns 1 to 0 and park returns immediately.

If you call park again, it will block (because permit is 0, it will block here until permit is 1), and unpark will set permit to 1. Each thread has an associated permit, and at most one permit. Repeated calls to unpark do not accumulate credentials.

Image understanding

A thread blocking requires a permit, of which there is at most one

When the park method is called

  • If there is a credential, it will directly consume the credential and exit normally.
  • If there are no credentials, you must block until the credentials are available.

Unpark, on the other hand, will add one certificate, but there can be only one certificate at most, and the sum is invalid.

The problem summary

Why is it possible to wake up a thread and then block it?

Because unpark gets a certificate and then calls the park method, it can legitimately consume the certificate, so it will not be blocked.

Why wake up twice and then block twice, but end up blocking the thread?

Because the number of credentials is 1 at most, two consecutive calls to unpark and one call to unpark have the same effect, only one more certificate will be added: but two calls to Park need to consume two certificates, which cannot be released because of insufficient certificates.