可重入锁又名递归锁
是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提:锁对象是同一个对象),不会因为之前已经获取过还没释放而阻塞.
Java中的Synchronized和ReentrantLock都是可重入锁,可重入锁的优点是可一定程度避免死锁
LockSupport:用于创建锁和其它同步类的基本线程阻塞原语
线程等待唤醒机制
LockSupport中的park()和unpark()的作用分别是阻塞线程和解除阻塞线程
LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可
许可只有两个值1和0,默认是0
可以把许可看成是一种(0,1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1
LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以在线程任意位置阻塞,阻塞之后有对应的唤醒方法.LockSupport内部调用Unsafe类的native方法
为什么可以先唤醒线程后阻塞线程? 因为unpark获得了一个许可,之后再调用park方法,就能直接使用许可消费,不会阻塞,跟唤醒和阻塞的顺序无关
为什么唤醒两次后阻塞两次,最终结果还是会阻塞线程? 因为许可的数量最对为1,连续调用两次unpark和调用一次unpark的效果一样,许可的数量为1.而调用两次park需要消费两个许可,许可不够,不能放行,所以阻塞
/**
* 传统的synchronized和Lock实现通知唤醒的约束
* 1.线程先要获得并持有锁,必须在锁块中(synchronized或lock)
* 2.必须要先等待后唤醒,线程才能被唤醒
*/
public static void lockSupportDemo(){
Thread a =new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName()+"...weak up");
},"A");
a.start();
Thread b =new Thread(()->{
LockSupport.unpark(a);
System.out.println(Thread.currentThread().getName()+"...unpark");
},"B");
b.start();
}