本文主要学习了LockSupport的原理和相关操作。
1 是什么

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,在内部使用一个许可证的概念来实现阻塞和唤醒,每个线程都有一个许可证,许可证只有1和0两个值,默认是0。

LockSupport中的park()和unpark()的作用分别是阻塞线程和解除阻塞线程,park()方法会在许可证可用时执行,unpark()方法会在许可证不可用时提供许可证。

归根结底,LockSupport调用的Unsafe中的native代码。

2 比较

1)使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程。

必须在synchronized内部执行,否则抛出IllegalMonitorStateException。

必须先执行wait()方法再执行notify()方法,即只能在wait()方法后使用notify()方法唤醒,否则程序将一直等待无法被唤醒。

2)使用Condition的await()方法让线程等待,使用Condition的signal()方法唤醒线程。

必须和Lock组队使用,否则抛出IllegalMonitorStateException。

只能在wait()方法后使用notify()方法唤醒,否则程序将一直等待无法被唤醒。

3)使用LockSupport的park()方法让线程等待,使用LockSupport的uppark()方法唤醒线程。

不需要在任何方法块内执行,park()方法和uppark()方法都是静态方法,可以在任何地方执行。

使用顺序无要求,即便uppark()方法提前,也能保证park()方法被唤醒。

3 使用

代码如下:

 1 public static void main(String[] args) {
 2     Thread a = new Thread(()->{
 3         try {
 4             Thread.sleep(3000);
 5         } catch (InterruptedException e) {
 6             e.printStackTrace();
 7         }
 8         System.out.println(Thread.currentThread().getName() + "-----进入");
 9         LockSupport.park();
10         System.out.println(Thread.currentThread().getName() + "-----执行");
11     }, "a");
12     a.start();
13     Thread b = new Thread(()->{
14         System.out.println(Thread.currentThread().getName() + "-----进入");
15         LockSupport.unpark(a);
16         System.out.println(Thread.currentThread().getName() + "-----执行");
17     }, "b");
18     b.start();
19 }

结果如下:

1 b-----进入
2 b-----执行
3 // 等待三秒
4 a-----进入
5 a-----执行
4 总结

LockSuport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞和唤醒。LockSupport底层调用的Unsafe中的native代码。

调用park()方法,如果凭证为1,则将凭证变成0,同时park()方法立即返回并继续执行,如果凭证为0则会阻塞,直到unpark()方法执行将凭证从0变为1。

调用unpark()方法会将凭证从0变成1,多次调用unpark()的结果仍会使得凭证为1,不会导致凭证累加,凭证只有0和1两种取值。