1.概念
LockSupport是用来进行线程的通信的,是一个线程阻塞的工具类,其中里面的方法都是静态方法,park()和unpark()的作用分别是阻塞线程和唤醒线程。
2.线程等待和唤醒机制
-
方式一:使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程
-
方式二:使用JUC包中的Condition的await()方法让线程等待,使用signal()方法唤醒线程
-
方式三:LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程
方式一必须在同步代码块或者同步方法中成对使用,先wait后notify才能正常使用。
方式二必须先获取锁后才能使用,并且是先await后signal才能正常使用。
3.LockSupport的强大之处
LockSupport类中使用了一种名为Permit(许可证)的概念来实现阻塞和唤醒线程的功能,而且许可证只能有一个,不能累加。
park:许可证默认没有所以会阻塞,等到发放许可才能唤醒。
unpark:发放许可证,自动唤醒等待的线程。
public class LockSupportDemo {public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t -----------come in");LockSupport.park(); //阻塞System.out.println(Thread.currentThread().getName() + "\t ----------被唤醒");}, "t1");t1.start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {LockSupport.unpark(t1);//发放许可System.out.println(Thread.currentThread().getName() + "\t ----------发出通知");}, "t2").start();}
}
形象的理解:线程阻塞时需要消耗凭证,这个凭证最多只有一个,当调用park时,如果有许可,那么就直接消耗,继续向下进行,如果没有,则阻塞等待许可证的发放。当调用unpark时,发放一个许可证,多次调用不会累加。
4.面试高频题
4.1为什么LockSupport可以突破wait/notify的原有调用顺序?
因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞,先发放了凭证后续可以畅通无阻。
4.2为什么连续调用两次unpark方法,再调用两次park方法,还是会阻塞?
因为凭证的数量最大为1,而调用两次park方法却需要两个许可,证不够,所以会阻塞。