AbstractQueuedSynchronizer
- 该类是一个实现同步器的框架, 包含了一个FIFO队列, 一个state
- state值:0代表unlocked state,1代表locked state
使用方法
- 继承AbstractQueuedSynchronizer
- 实现tryAcquire(int arg)
- 实现tryRelease(int arg)
- 实现tryAcquireShared(int arg)
- 实现tryReleaseShared(int arg)
原理
- 获取锁–独享模式
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
最终会调用我们实现的trytryAcquire(). 如果返回true说明获取锁成功, 如果返回false说明获取锁失败, 那就把当前线程添加到FIFO队列中, 并调用park将线程挂起。
- 释放锁–独享模式
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
最终会调用我们实现的tryRelease, 返回true说明释放锁成功, 那么就将FIFO队列中的挂起的线程通过unpark恢复。
- 获取锁–共享模式
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
//这里实现唤醒共享模式的节点
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
共享模式在获取到锁之后会调用setHeadAndPropagate, doReleaseShared唤醒队列中是共享模式的节点。
- 释放锁–共享模式
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
可重入锁ReentrantLock
- 可重入锁意思是, 拥有该锁的线程可以多次拥有该锁, 不需要等待.
- 公平锁:线程A想要获取锁,如果FIFO队列中有等待的线程,那么线程A一定会进入到FIFO排队等待.
- 不公平锁:线程A想要获取锁,不管FIFO队列中是否有等待的线程,线程A会与他们一起竞争锁资源.
- 原理如下
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//公平锁的实现,如果当前FIFO队列中有等待的线程,那么就加入到等待队列中
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//可重入锁的实现,如果当前线程已经拥有锁了,那么计数器+1.
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//不公平锁的实现,只要调用了获取锁的方法就会去竞争资源.
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//可重入锁的实现,如果当前线程已经拥有锁了,那么计数器+1.
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
//获取几次锁,在释放时就要释放几次。
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
CountDownLatch
- 基于共享模式实现的.
int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void countDown() {
sync.releaseShared(1);
}
- 当调用await时
- 调用tryAcquireShared
- 如果返回值<0, 把线程加入到FIFO队列中
- 挂起线程
- 当调用countDown时
- 调用tryReleaseShared
- 如果state != 0 就返回失败
- 如果state == 0那么就唤醒队列中共享模式的线程. (独占模式中只唤醒FIFO队列中的一个线程)
Condition
- 锁中Condition提供的await, signal相当于 synchronized中的wait, notify.
await流程:
1. 创建节点加入到条件队列
2. 释放互斥锁
3. 只要没有转移到同步队列就阻塞(等待其他线程调用signal/signalAll或是被中断)
4. 重新获取互斥锁
signal流程:
1. 将队列中第一个节点转移到同步队列
2. 根据情况决定是否要唤醒对应线程
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦