syn和ReentrantLock都是可重入同步锁,可一定程度避免死锁。可重入锁:一个线程中的多个流程可以获取同一把锁,持有这把同步锁可以再次进入。自己可以获取自己的内部锁。
syn的重入的实现机理
LockSupport 的方法和作用
相当于wait和notify的提升,LockSupport 中的park()和unpark()的作用分别是阻塞线程和解除阻塞线程。底层还是unsafe,native。
park的底层许可证permit默认是0,所以一开始调用park()方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park就会被唤醒,然后将permit再次设置为0并返回。
unpark将thread线程的许可permit设置为1(多次调用unpark方法,不会累加,permit值还是为1)会自动唤醒thread线程,即之前阻塞中的LockSupport.park()方法会立即返回。
之前传统的syn和ReentrantLock都有约束:线程先要获得并持有锁,必须在锁块中;必须要先等待后唤醒,线程才能够被唤醒。
LockSupport的底层原理
这里如果调用两次unpark方法会被阻塞,因为unpark方法相当于发放许可证,许可证最多为1,超过1个就会被阻塞。调用多次还是只有一个许可证。而调用两次park要消耗2个,不能放行。
JUC的重要基石AQS(AbstractQueuedSynchronizer,抽象的队列同步器)
抽象类,是作为父类被其他类继承的。通过内置的FIFO队列来完成资源获取线程的排队工作,并通过一个volatile的int类型表示持有锁的状态。是个虚拟的双向队列。
和AQS有关的:如ReentrantLock,CountDownLatch,ReentrantReadWriteLock,Semaphore都继承了AQS。
AQS使用一个volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个node节点来实现锁的分配,通过CAS完成对state值的修改。
类似hashmap里面的KV键值对,也是封装成node类型的数组进行存放。
AQS=state状态位+CLH队列
(1)其中private volatile int state,0表示没人,自由状态可以去办理;大于等于1表示有人占用窗口等着去
(2)CLH队列(三个大牛名字组成的),为一个双向队列
(3)node的等待状态waitstate成员变量,volatile int waitStatus 等候区其他线程的等待状态,队列中每个排队的个体就是一个node。
Node=waitStatus+前后指针指向
AQS同步队列的基本结构
AQS源码解读
模板设计模式,如果不实现这个父类就抛异常
B会进入等待线程,但是第一个node不是B而是一个虚拟节点
2.调用addwaiter方法下一步就是第一个等待线程B enq入队 *** 作
让抢到受理的B去,原来的虚拟节点没有引用被GC回收,原来的B成为新的虚拟节点
具体流程图见链接:AQS流程图
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)