LockSupport

LockSupport from wait/notify/notifyAll, condition. Await/signal/signalAll to start

LockSupport is used in many places in JUC packages. For example, in ReentrantLock we wrote earlier, locksupport.park () is queued to wait for the previous thread unpark to acquire the lock

Wait /notify, await/signal, park/unpark

A, wait to notify

Wait Nofity explained this in detail in the previous article. This is just a simple and useful comparison to LockSupport

class TestWaitNotify {
    public Object obj = new Object();
    public static void main(String[] args) {
        TestWaitNotify test = new TestWaitNotify();
        new Thread(test::xiaoqiang).start();
        new Thread(test::xiaoyueyue).start();
    }

    /** * Xiaoqiang drinks water */
    public void xiaoqiang(a){
        synchronized (obj){
            while (true) {try{
                    System.out.println("Johnny drinks water.");
                    // Tell someone to drink water
                    obj.notify();
                    / / wait
                    obj.wait();
                } catch(Exception e){ e.printStackTrace(); }}}}/** * Xiaoyueyue drinks water */
    public void xiaoyueyue(a){
        synchronized (obj){
            while (true) {try{
                    System.out.println("Little Yueyue drinks water.");
                    // Tell someone to drink water
                    obj.notify();
                    / / wait
                    obj.wait();
                } catch(Exception e){ e.printStackTrace(); }}}}} Output: Jack water Jack water Jack water Jack water Jack water Jack water Jack water...Copy the code

Jack Bauer finished drinking notice others can drink, and then wait for yourself

Xiaoyueyue received notice, drink water, drink out of notice others can drink, and then wait for yourself

And so on…

Wait /notify/notifyAll

1.Must be synchronized code block or synchronized modification method Otherwise you will quote exception: Java. Lang. IllegalMonitorStateException2.Nofity is invoked only after the wait method is called.3.An interrupt interrupts a waitCopy the code
Second, await signal
class TestAwaitSignal {
    Lock lock = new ReentrantLock();
    Condition cd = lock.newCondition();
    public static void main(String[] args) {
        TestAwaitSignal test = new TestAwaitSignal();

        new Thread(test::xiaoqiang).start();
        new Thread(test::xiaoyueyue).start();
    }

    /** * Xiaoqiang drinks water */
    public void xiaoqiang(a){
        try {
            lock.lock();
            while (true) {try{
                    System.out.println("Johnny drinks water.");
                    // Signal someone to drink water
                    cd.signal();
                    / / await
                    cd.await();
                } catch(Exception e){ e.printStackTrace(); }}}catch (Exception e){
            e.printStackTrace();
        } finally{ lock.unlock(); }}/** * Xiaoyueyue drinks water */
    public void xiaoyueyue(a){
        try {
            lock.lock();
            while (true) {try{
                    System.out.println("Little Yueyue drinks water.");
                    // Signal someone to drink water
                    cd.signal();
                    / / await
                    cd.await();
                } catch(Exception e){ e.printStackTrace(); }}}catch (Exception e){
            e.printStackTrace();
        } finally{ lock.unlock(); }}} Output results: Jack water Jack water Jack water Jack water Jack water Jack water Jack water Jack water Jack water...Copy the code

Await /signal/signalAll

1.Must be carried out on the lock lock block of code Otherwise you will quote IllegalMonitorStateException anomalies2.Lock must release the lock manually in finally3.Signal must be called after await or it will not work4.Condition. Await is more interruptible than wait, and stops when it reaches a specified point.5.A lock can create multiple conditions that do not interfere with each other.Copy the code

Third, LockSupport

3.1 the use of

This is to give very good things

A: Park /pɑːk/

Unpark pulls the car out of the parking lot

From the story of walking into park/ Unpark, Xiaoqiang drove his car into a parking lot park for a while, and then he couldn’t get out. He had to park in the parking lot until Xiaoyueyue gave him the parking ticket unpark, and then he could go out

Parking examples:

class TestParkUnpark {

    public static void main(String[] args) throws InterruptedException {
        TestParkUnpark test = new TestParkUnpark();
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();

        Thread.sleep(5000);
        // Xiao Yueyue gives parking coupons
        new Thread(()->{
            test.xiaoyueyue(thread);
        }).start();
    }

    /** * Jack enters the parking lot */
    public void xiaoqiang(a){
            System.out.println("Park and wait to get out of the parking lot.");
            LockSupport.park();
            System.out.println("I'm out!!");
    }

    /** * Xiaoyueyue gives parking tickets */
    public void xiaoyueyue(Thread thread){
        System.out.println("Give jack Bauer a parking ticket for those idiots."); LockSupport.unpark(thread); }} Output: parking waiting for the parking lot to xiaoqiang that two fool to send a parking coupon I came out!!Copy the code

I mean, obviously,

1. The biggest difference between LockSupport and wait/ conditional. await is that it does not lock and does not need to be used in lock blocksCopy the code
3.2 Out of order

LockSupport also has another feature that unpark can be implemented before park. That is, xiaoyueyue gives him the parking ticket unpark before the two idiots go to the parking lot. When he wants to leave, he does not need to obtain the parking ticket unpark again.

class TestParkUnpark02 {

    public static void main(String[] args) throws InterruptedException {
        TestParkUnpark02 test = new TestParkUnpark02();
        Thread thread = new Thread(test::xiaoqiang);

        // Enter the parking lot
        thread.start();

        // Xiao Yueyue gives the parking ticket first
        new Thread(()->{
            test.xiaoyueyue(thread);
        }).start();

    }

    /** * Jack enters the parking lot */
    public void xiaoqiang(a)   {
            try {
                // Out in the open
                Thread.sleep(10000);
                // Into the parking lot
                System.out.println("Park and wait to get out of the parking lot.");
                LockSupport.park();
                System.out.println("I'm out!!");
            } catch (Exception e){

            }
    }

    /** * Xiaoyueyue gives parking tickets */
    public void xiaoyueyue(Thread thread){
        System.out.println("Give jack Bauer a parking ticket for those idiots."); LockSupport.unpark(thread); }} Output results: give xiaoqiang that two fool to send a parking coupon parking waiting for a parking lot I came out!!Copy the code
3.3 Interruptible Timeout return Specifies the waiting time to return
class TestParkUnpark03 {
    public static void main(String[] args)   {
        TestParkUnpark03 test = new TestParkUnpark03();
        // Can interrupt stop park
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();
        thread.interrupt();


    }
    /**
     *  可中断
     */
    public void xiaoqiang(a)   {
        // Into the parking lot
        System.out.println("Park and wait to get out of the parking lot.");
        LockSupport.park();
        boolean interrupted = Thread.currentThread().isInterrupted();
        if (interrupted){
            System.out.println("Interrupted break-in.");
        } else {
            System.out.println("Got the ticket I came out!!"); }}}Copy the code
class TestParkUnpark04 {
    public static void main(String[] args)   {
        TestParkUnpark04 test = new TestParkUnpark04();
        / / can be timed out
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();


    }
    /** ** can timeout */
    public void xiaoqiang(a)   {
        // Into the parking lot
        System.out.println("Park and wait to get out of the parking lot.");
        // Go out after 5 seconds
        long nanos = TimeUnit.SECONDS.toNanos(5);
        LockSupport.parkNanos(nanos);
        System.out.println("End park either gave the ticket or Jack Bauer spent hours with the doorman letting him out."); }}Copy the code
class TestParkUnpark04 {
    public static void main(String[] args)   {
        TestParkUnpark04 test = new TestParkUnpark04();
        // Stop the park at this point
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();


    }
    /** * stop park */
    public void xiaoqiang(a)   {
        // Into the parking lot
        System.out.println("Park and wait to get out of the parking lot.");
        // Go out after 10 seconds
        long nanos = TimeUnit.SECONDS.toMillis(10);
        Date date= new Date(System.currentTimeMillis()+nanos);
        // Stop at the specified time
        LockSupport.parkUntil(date.getTime());
        System.out.println("End park either gave the ticket or Jack Bauer spent a long time with the guard and let him out or at night (the appointed time) the guard didn't sneak out."); }}Copy the code
3.4 There is one more feature

At first glance, this feature doesn’t seem very useful.

class TestParkUnpark04 {
    public static void main(String[] args)   {
        TestParkUnpark04 test = new TestParkUnpark04();
        new Thread(test::xiaoqiang01,Threads "001").start();
        new Thread(test::xiaoqiang02,Threads "002").start();

    }

    public void xiaoqiang01(a)   {
        // An object is passed in
        LockSupport.park();
    }
    public void xiaoqiang02(a)   {
        // An object is passed in
        LockSupport.park(newParkParam()); }}class ParkParam{}Copy the code

We use JPS to find the current Java process and jStack to see the stack information

CMD 2. JPS 11672 TestParkUnpark04 3. Jstack -l 11672 Os_prio =0 TID =0x000000001e042800 NID = 0x263C waiting on condition [0x000000001eAFF000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000076bbb1a20> (a vip.freeedu.ParkParam) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at vip.freeedu.TestParkUnpark04.xiaoqiang02(TestParkUnpark04.java:25) at vip.freeedu.TestParkUnpark04$$Lambda$2/990368553.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) Locked ownable synchronizers: -none "Thread 001" #11 PRIo =5 OS_PRIO =0 TID = 0x000000001E03F800 nID = 0x25FC waiting on condition [0x000000001e9FF000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304) at vip.freeedu.TestParkUnpark04.xiaoqiang01(TestParkUnpark04.java:21) at vip.freeedu.TestParkUnpark04$$Lambda$1/2003749087.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)Copy the code

– Parking for wait for XXXX

In this way, when we troubleshoot problems, it is easy to know where the problem is. Each park has a different object, so that it is easy to locate

3.5 LockSupport** advantages come out
1. Do not mix with lock!! 2. You can unpark and get the parking ticket when you are in the park, you can pass with the parking ticket directly!! 3. You can stop waiting for a timeout. Wait await is supported. 4. Await support 5. Interrupt; Wait await supports await await supports not responding to interruptsCopy the code

Object’s wait also supports timeout

3.6 note:Unpark cannot be accumulated

The implementation principle of park and unpark. I looked at the hotspot implementation and didn’t get it, but I saw that the comments probably meant something like this,

There is a flag bit **_event**,

3.7 park

The value of **_event** is determined when park is called

  1. If it is -1, the data is invalid

  2. If it is 1, set it to 0 to return (go straight through without blocking), which is equivalent to getting out of the parking lot smoothly with a parking ticket (unpark then park)

  3. If 0 then set **_event** to -1

void os::PlatformEvent::park() {       // AKA "down()"
  // Transitions for _event:
  // -1 => -1 : illegal
  // 1 => 0 : pass - return immediately
  // 0 => -1 : block; then set _event to 0 before returning

Copy the code

3.8 unpark

The _event** value is determined when unpark**** is called

  1. If it’s 0, set **_event** to 1 that’s why unpark can be called before park, because it’s set to 1 and then park will use that value, okay

  2. If it’s one, it doesn’t accumulate that’s why unpark can only be used once for park, right

  3. If it is -1 then set **_event** to 0 or 1 to wake up the target thread

void os::PlatformEvent::unpark() {
  // Transitions for _event:
  // 0 => 1 : just return
  // 1 => 1 : just return
  // -1 => either 0 or 1; must signal target thread
  // That is, we can safely transition _event from -1 to either
  // 0 or 1.

Copy the code

Welcome to our official account: