概述
java.util.concurrent 并发工具包
Lock
Lock是个接口,ReentrantLock唯一实现Lock的类
synchronized和ReentrantLock都支持重入锁
当多个线程争抢锁,其他的会阻塞
AQS同步工具
1、独占->互斥
2、共享->读写锁
AQS的基本实现
1、一个共享数据类记录锁的状态(有锁/无锁)
state:锁标记,0是无锁、大于0是有锁和重入次数,通过cas实现原子性(乐观锁)
Node节点信息
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
a、b、c线程执行lock()争抢锁流程(AQS)
1、a先执行lock.lock()获取到锁后获取到了,执行业务代码
2、b在执行lock.lock()没有抢到锁时会被包装成Node节点加入AQS队列并挂起,每个Node节点中会有一个pre指向上一个被挂起的Node和一个next指向下一个进来被挂起的Node,AQS队列中第一个Node节点中thread指向为空,表示获得所的线程,第二个Node才是线程b
3、c接着执行lock.lock()也没有抢到锁,然后被包装成Node,c的Node的pre会指向b的Node,b的Node的next会指向c的Node,这样多个Node就组成了一个双向链表
4、当a走完业务代码执行lock.unlock()释放了锁后,会移除第一个Node节点并唤起AQS队列中第二个Node也就是b并继续执行业务代码
lock.Condition
a、b线程执行lock()争抢锁,a在释放锁钱执行condition.await流程(AQS)
1、2同上
3、当a走业务代码执行condition.await后,会释放当前的锁并清空重入次数,然后被阻塞并加入到condition队列中,然后会移除第一个Node节点并唤起AQS队列中第二个Node也就是b并继续执行业务代码
4、b执行lock.lock抢到锁后执行完业务并执行condition.signal(),就会把condition队列中的第一个Node也就是A加入到AQS队列中去等待被唤醒重新争抢锁
CountDownLatch/CycliBarrier
Semaphore 限流
阻塞队列
通过ReencurrentLock和condition实现
ArrayBlockQueue
LinkBlockQueue
DelayQueue
SynchrousQueue
Atomic原子操作的原理
通过一个do-while循环不断去查询再CAS操作直到成功才退出循环
最后
以上就是轻松小天鹅为你收集整理的Lock的基本使用及原理笔记的全部内容,希望文章能够帮你解决Lock的基本使用及原理笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复