当前位置:网站首页>Tool class under JUC package, its name is locksupport! Did you make it?

Tool class under JUC package, its name is locksupport! Did you make it?

2020-11-06 01:16:00 Liu Zhihang

Preface

LockSupport yes JUC A tool class commonly used in , The main function is to suspend and wake the thread . In the reading JUC Source code often see , So it's necessary to understand .

official account :liuzhihangs , Record the skills in work study 、 Development and source notes ; From time to time to share some of the life experience . You are welcome to guide !

Introduce

The basic thread blocking primitive creates locks and other synchronization classes .Basic thread blocking primitives for creating locks and other synchronization classes.

LockSupport Class is associated with a permission for each thread that uses it ( In a sense Semaphore class ). If the license is available , call park Will return immediately , And consume it in the process ; Otherwise it may block . If the license is not available , You can call unpark Make the license available .( But with Semaphore Different , Permits can't accumulate . There is at most one .)

Method park and unpark Provides an effective means of blocking and unlocking threads without deadlock problems , and Thread.suspend and Thread.resume It can't be used for this purpose : Because of the license , One thread call park And another thread tries to unpark The competition between them will remain active . Besides , If the caller thread is interrupted ,park Will return , And support setting timeout . The park Method may also return at any other time ,“ There is no reason ”, Therefore, it is usually necessary to re check the condition after a call in a cycle . In that sense park As “ Busy waiting ” Don't waste too much time on spin optimization , But it has to be paired unpark Use .

These three forms of park And support blocker Object parameters . When a thread is blocked, it is allowed to use monitoring and diagnostic tools , To determine the cause of the thread blocking .( Diagnostic tools can be used getBlocker(Thread) Method .) It is also recommended to use with blocker Parametric park Method , The usual way is blocker Set to this .

The meaning of the above can be summed up as follows :

  1. The license (permit) The upper limit of is 1, That is to say, only 0 or 1 .
  2. park: Without permission ,permit by 0 , call park It will block ; When you have permission ,permit by 1 , call park A permit will be deducted , Then return .
  3. unpark: Without permission ,permit by 0 , call unpark Will add a license , Because the license limit is 1 , So many calls are only for 1 individual .
  4. There is no permission at the beginning of the thread .
  5. park If the current thread is interrupted , Will return immediately , It doesn't throw an interrupt exception .
  6. park Method calls are generally placed in a loop judgment body .

It's roughly as shown :

rGm1AX

Here is the example in the source code annotation :

/**
 * FIFO  An exclusive lock 
 */
class FIFOMutex {
   private final AtomicBoolean locked = new AtomicBoolean(false);
   private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();

   public void lock() {
     boolean wasInterrupted = false;
     Thread current = Thread.currentThread();
     waiters.add(current);

     // Block while not first in queue or cannot acquire lock
     //  Not at the head of the queue , Or the lock is occupied , The block ,  Only the queue header can obtain the lock 
     while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
       LockSupport.park(this);
       if (Thread.interrupted()) // ignore interrupts while waiting
         wasInterrupted = true;
     }

     waiters.remove();
     if (wasInterrupted)          // reassert interrupt status on exit
       current.interrupt();
   }

   public void unlock() {
     locked.set(false);
     LockSupport.unpark(waiters.peek());
   }
 }

verification

Does the thread have permission to start ?

public class LockSupportTest {

    public static void main(String[] args) {

        System.out.println(" Start execution ……");

        LockSupport.park();

        System.out.println("LockSupport park  after ……");

    }
}
  1. After execution, you will find , Code in park Block at . explain , There is no permission for threads to start with .

Add licenses and consume licenses

public class LockSupportTest {

    public static void main(String[] args) {

        System.out.println(" Start execution ……");

        LockSupport.unpark(Thread.currentThread());

        System.out.println(" perform  - park");
        
        LockSupport.park();

        System.out.println("LockSupport park  after ……");

    }

}
public class LockSupportTest {

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(" Threads  " + Thread.currentThread().getName() + " Start execution  park");
                LockSupport.park(this);
                System.out.println(" Threads  " + Thread.currentThread().getName() + " perform  park  end ");
            }
        });

        thread.start();
        //  Guarantee   The thread above executes first , And then the main thread 
        Thread.sleep(5000);
        System.out.println(" Start execution  unpark(thread)");
        LockSupport.unpark(thread);
        Thread.sleep(5000);
        System.out.println(" perform  unpark(thread)  end ");

    }

}

From the above example, we can see that :

  1. perform unpark You can give a certificate to the specified thread .
  2. Thread is currently being park Blocking , At this point, after giving the certificate , park Will consume certificates , And then go ahead and do it .

The license limit is 1


public class LockSupportTest {

    public static void main(String[] args) {

        System.out.println("unpark 1 Time ");
        LockSupport.unpark(Thread.currentThread());
        System.out.println("unpark 2 Time ");
        LockSupport.unpark(Thread.currentThread());

        System.out.println(" perform  - park 1  Time ");
        LockSupport.park();
        System.out.println(" perform  - park 2  Time ");
        LockSupport.park();
        
        System.out.println("LockSupport park  after ……");

    }

}
  1. Thread blocking , It can be seen that permit There can only be one

Interruptions can make park Continuing execution does not throw an exception

public class LockSupportTest {
    public static void main(String[] args)  {

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(" Threads  " + Thread.currentThread().getName() + " Start execution  park");
                LockSupport.park(this);
                System.out.println(" Threads  " + Thread.currentThread().getName() + " perform  park  end ");

                System.out.println(" Threads  " + Thread.currentThread().getName() + " Start execution  park  The second time ");
                LockSupport.park(this);
                System.out.println(" Threads  " + Thread.currentThread().getName() + " perform  park  The second time   end ");

            }
        });

        try {
            thread.start();
            //  Guarantee   The thread above executes first , And then the main thread 
            Thread.sleep(5000);
            System.out.println(" Start execution  unpark(thread)");
            // LockSupport.unpark(thread);
            thread.interrupt();
            Thread.sleep(5000);
            System.out.println(" perform  unpark(thread)  end ");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Output results :

/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/bin/java ...
 Threads  Thread-0 Start execution  park
 Start execution  unpark(thread)
 Threads  Thread-0 perform  park  end 
 Threads  Thread-0 Start execution  park  The second time 
 Threads  Thread-0 perform  park  The second time   end 
 perform  unpark(thread)  end 
  1. You can see that thread breaks ,park Will continue to execute , And there's no exception thrown .
  2. thread.interrupt(); After call , Set thread interrupt flag ,unpark No clear interrupt flag , the second park Will continue to carry out .

Using diagnostic tools

liuzhihang % > jps
76690 LockSupportTest
77130 Jps
liuzhihang % > jstack 77265
...
"main" #1 prio=5 os_prio=31 tid=0x00007f7f3e80a000 nid=0xe03 waiting on condition [0x000070000dfcd000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304)
        at com.liuzhihang.source.LockSupportTest.main(LockSupportTest.java:14)
  1. The middle part is omitted , But you can see that the thread enters WAITING state

Source code analysis


public class LockSupport {

    private static final sun.misc.Unsafe UNSAFE;

    /**
     *  For threads  thread  Set up a license 
     *  No license , Add a license , With permission , Do not add 
     *  If the thread is because of  park  Blocked ,  After adding a license , It will clear the blocking state 
     */
    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }

    /**
     *  With permission , Use the license 
     *  No permission , Blocking threads , Until permission is obtained 
     *  Pass on  blocker  To facilitate the use of diagnostic tools 
     */
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }

    /**
     *  Set thread's  blocker  attribute 
     */
    private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn't need a write barrier here.
        UNSAFE.putObject(t, parkBlockerOffset, arg);
    }
}

LockSupport Of park unpark Method , The actual call is the underlying Unsafe Class native Method .


public final class Unsafe {
    
    public native void unpark(Object var1);

    public native void park(boolean var1, long var2);
}

Now that we call Unsafe We can't stop here .

ffecad2c8644bab7d152be118c31722d

hotspot Source code

This is the source code of the download official package , Read and review the information to understand the general logic , What's unclear , Hope to be guided out .

You can also skip and look at the conclusion directly .

see jdk Source code
http://hg.openjdk.java.net/jd...

This is in the form of os_linux Code, for example
http://hg.openjdk.java.net/jd...

c-parker
c-park
c-unpark

  1. At the bottom, a _counter By updating the _counter To indicate whether there is proof .
  2. stay park when , Judge _counter by 0, Then block and wait , by 1 Then get updated to 0 And back to .
  3. stay unpark when , Judge _counter by 0, Then give proof , And wake up the thread , by 1 Then return directly .

summary

The conclusion is the same as expected .

  1. The license (permit) The upper limit of is 1, That is to say, only 0 or 1 .
  2. park: Without permission ,permit by 0 , call park It will block ; When you have permission ,permit by 1 , call park A permit will be deducted , Then return .
  3. unpark: Without permission ,permit by 0 , call unpark Will add a license , Because the license limit is 1 , So many calls are only for 1 individual .
  4. There is no permission at the beginning of the thread .
  5. park If the current thread is interrupted , Will return immediately , It doesn't throw an interrupt exception .

Expand

  • park/unpark and wait/notify difference
  1. park Block the current thread ,unpark Wake up the specified thread .
  2. wait() It needs to be used in combination with locks , And release the lock resource , If no timeout is set , You need to notify() Wake up the . and notify() The wake-up thread is random .

版权声明
本文为[Liu Zhihang]所创,转载请带上原文链接,感谢