常见JUC类代码解析
ReentrantLock
ReetrantLock是一种类似Synchronized的一种互斥锁实现代码同步执行的方式。它是java语言自己实比Synchronized使用更加灵活.
ReetrantLock和Sychronized区别
- ReentrantLock是java自己实现的一种同步锁机制,Synchronized是调用本地方法实现
- ReentrantLock 支持公平锁和非公平锁,Synchronized只支持 非公平锁
- ReentrantLock 要主动通过unlock释放锁,Synchronized不需要释放锁
- ReentrantLock可以通过tryLock方法返回boolean来尝试获取锁,可以根据返回结果决定是否往下执行,Synchronized获取不到锁,就会一直尝试获取锁,不能通过程序控制。
示例代码
public class RentrantLockDemo {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
int maxLength = 5;
Queue<String> data = new LinkedList<String>();
Producer producer = new Producer(lock, condition, maxLength, data);
Consumer consumer = new Consumer(lock, condition, maxLength, data);
new Thread(producer).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private Lock lock;
private Condition condition;
private int maxLength;
private Queue<String> data;
public Producer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
this.lock = lock;
this.condition = condition;
this.maxLength = maxLength;
this.data = data;
}
@Override
public void run() {
int count = 0;
while (true) {
//加锁
lock.lock();
while (data.size() == maxLength) {
System.out.println("生产者队列满了,等待");
try {
//手动await进入等待队列,释放线程 相当于Synchronized的wait
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产者生产消息:" + (++count));
data.add(String.valueOf(count));
//唤醒其他线程等待线程 相当于Sychronized的notify
condition.signal();
//释放锁
lock.unlock();
}
}
}
class Consumer implements Runnable {
private Lock lock;
private Condition condition;
private int maxLength;
private Queue<String> data;
public Consumer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
this.lock = lock;
this.condition = condition;
this.maxLength = maxLength;
this.data = data;
}
@Override
public void run() {
while (true) {
lock.lock();
while (data.size() == 0) {
System.out.println("消费者队列空了,等待");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费消息:" + data.remove());
condition.signal();
lock.unlock();
}
}
}
类图

核心对象
-
AbstractOwnableSynchronizer: 主要用于存储ReetrantLock获取锁的线程,和获取锁线程的state(在ReetrantLock特指重入次数)
-
AbstractQueueSynchronizer: AQS队列,里面维护了双向链表和单向链表以及操作的Api,用于实现ReetrantLock锁,和Condition阻塞队列,实现互斥锁和锁等待的功能。
-
Node 节点信息,里面包含Thread和state 是对线程 和 线程状态的一个封装
-
Sync接口是ReetrantLock的内部类接口,
它有两个内部类实现 NonfairSync非公平锁实现,FairSync公平锁的实现
核心流程
以非公平锁的实现为例
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//无锁状态下尝试获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//竞争无锁失败,进入锁的重入或阻塞
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
三个核心方法
- tryAcquire
假设ThreadA执行tryAcquire成功

final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取当前持有锁线程的重入次数
int c = getState();
//如果重入次数为0 无锁,尝试竞争锁
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//如果持有锁的线程 和 当前线程是同一线程 增加重入次数返回true结束方法
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//返回false 进入线程阻塞逻辑
return false;
}
- (tryAcquire return false)=> addWaiter
private Node addWaiter(Node mode) {
//mode 为 Node.EXCLUSIVE 代表排它锁的实现
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
//AQS队列中已经存在节点 直接尝试加入到AQS尾部
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//加入尾部节点失败或者AQS队列为空进入enq自旋直到将node加入到AQS尾节点
enq(node);
return node;
}
//将node加入到尾节点,同时返回上一次的尾结点
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
ThreadB 和 ThreadC 尝试抢占锁失败,加入到AQS队列

- 挂起阻塞队列中的线程 acquireQueued
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ThreadB 和 ThreadC park 挂起线程

ThreadA执行完任务释放锁,并唤醒AQS队列节点
//unlock -> 执行release方法 每次传入1
public final boolean release(int arg) {
//尝试释放锁 如果释放锁成功 即state=0 exclusiveOwnerThread=null
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒AQS的head的下一个线程
unparkSuccessor(h);
return true;
}
return false;
}
rotected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果state=0 exclusiveOwnerThread=null 则释放线程成功返回true
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
//唤醒AQS线程逻辑
//传入node为AQS的head
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
//尝试将haed的waitState 设置为 0
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//拿到head的下一个节点
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
//从尾部向头部遍历,找到一个SINGLE状态的有效节点节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
//唤醒上面的有效节点
LockSupport.unpark(s.thread);
}
/**
* Release action for shared mode -- signals successor and ensures
* propagation. (Note: For exclusive mode, release just amounts
* to calling unparkSuccessor of head if it needs signal.)
*/
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
回到线程park是的状态
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
//此处park阻塞线程
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//线程恢复之后执行
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
//返回线程的中断标识, 并将线程的中断标识复位
return Thread.interrupted();
}
//这是因为park的阻塞和我们wait、sleep不一样,这两种阻塞,如果被外部线程中断,会自动唤醒线程,并抛出InterruptException异常复位中断标识,而park方法并没有这类实现,需要我们手动实现中断响应
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
//然后自旋方法内进入下次循环
for (;;) {
final Node p = node.predecessor();
//将当前节点的threadB set到exclusiveOwnerThread
if (p == head && tryAcquire(arg)) {
//将原来的threadB的node设置为AQS头结点,setThread=null
setHead(node);
p.next = null; // help GC
failed = false;
//终止自旋,返回中断标识
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
//返回中断标识后 调用selfInterrupt
static void selfInterrupt() {
//将复位后的标识再次中断
Thread.currentThread().interrupt();
}
//这个时候我们可以在lock方法中通过Thread.currentThread.isInterrupted响应中断

Condition
Condition是ReentrantLock的衍生对象,通过ReentrantLock.newCondition()创建Condition对象,在同步代码块内通过Condition.await() 可以主动释放线程cpu时间片,进入waiting状态,作用和Synchronized的wait/notify一样,Condition提供了await()/single(),来实现加锁同步代码的等待和唤醒机制。
示例代码
public class RentrantLockDemo {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
int maxLength = 5;
Queue<String> data = new LinkedList<String>();
Producer producer = new Producer(lock, condition, maxLength, data);
Consumer consumer = new Consumer(lock, condition, maxLength, data);
new Thread(producer).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private Lock lock;
private Condition condition;
private int maxLength;
private Queue<String> data;
public Producer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
this.lock = lock;
this.condition = condition;
this.maxLength = maxLength;
this.data = data;
}
@Override
public void run() {
int count = 0;
while (true) {
//加锁
lock.lock();
while (data.size() == maxLength) {
System.out.println("生产者队列满了,等待");
try {
//手动await进入等待队列,释放线程 相当于Synchronized的wait
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产者生产消息:" + (++count));
data.add(String.valueOf(count));
//唤醒其他线程等待线程 相当于Sychronized的notify
condition.signal();
//释放锁
lock.unlock();
}
}
}
class Consumer implements Runnable {
private Lock lock;
private Condition condition;
private int maxLength;
private Queue<String> data;
public Consumer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
this.lock = lock;
this.condition = condition;
this.maxLength = maxLength;
this.data = data;
}
@Override
public void run() {
while (true) {
lock.lock();
while (data.size() == 0) {
System.out.println("消费者队列空了,等待");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费消息:" + data.remove());
condition.signal();
lock.unlock();
}
}
}

核心流程
countDownLatch.await()
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//尝试加入到Condition单向链表
Node node = addConditionWaiter();
//释放当前重入锁 记录重入次数,再次被唤醒时需要重新写入重入次数
//里面执行了unparkSuccessor(h) 方法会唤醒AQS的head.next节点线程
int savedState = fullyRelease(node);
//记录中断类型的字段
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
//挂起线程
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//通过singel方法node被转移到了AQS队列, 被唤醒之后需要将重入锁次数传入重新竞争锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
//清理cancelled状态的node
unlinkCancelledWaiters();
//根据中断标识 选择处理中断的方式(重新响应中断或者抛出interruptException异常)
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//加入单向Condition链表的方法
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
//判断节点是否在AQS队列 如果不在才需要park线程
final boolean isOnSyncQueue(Node node) {
//标识node在Condition队列,不在AQS,需要park挂起当前node线程
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
//快捷判断 在AQS的方法 因为Condition队列只有nextWaiter的关系
if (node.next != null) // If has successor, it must be on queue
return true;
/*
* node.prev can be non-null, but not yet on queue because
* the CAS to place it on queue can fail. So we have to
* traverse from tail to make sure it actually made it. It
* will always be near the tail in calls to this method, and
* unless the CAS failed (which is unlikely), it will be
* there, so we hardly ever traverse much.
*/
//上一步没有找到 就从AQS尾部查找node 判断是否在AQS
return findNodeFromTail(node);
}
countDownLatch.single()
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//将firstWaiter缓存到first局部变量
Node first = firstWaiter;
if (first != null)
//唤醒first节点
doSignal(first);
}
private void doSignal(Node first) {
do {
//firstWaiter = first.nextWaiter 将first.nextWaiter交给firstWaiter缓存
//如果first的下一个节点为空,说明condition队列空了,设置lastWaiter==null
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
//唤醒first之前将first.nextWaiter==null,帮助first GC
first.nextWaiter = null;
//transferForSignal(first) 尝试将first转移动到AQS队列
//(first = firstWaiter) != null 转移失败了,将first赋值为原来的first.nextWaiter,继续唤醒,知道唤醒一个有效对的Condition节点
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
//转移到AQS核心逻辑
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
//cas将节点的waitStatus从CONDITION-> node初始waitStatus:0
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
//失败说明唤醒失败,抛弃该node唤醒,唤醒它的nextWaiter
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
//cas成功后 enq将node加入到AQS队列 返回node在AQS中的prev节点
Node p = enq(node);
//拿到prev节点的waitStatus
int ws = p.waitStatus;
//如果prev节点的waitStatus为cancelled后者修改为SINGEL失败,可以提前唤醒node的线程
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
//提前唤醒node的线程,这是一种优化的方案,因为node迟早都要唤醒,虽然执行single的线程还没有挂起,但是唤醒之后反正要重新竞争锁不存在线程安全问题,并且如果prev节点是called状态,需要清理called需要时间,所以提前唤醒node,提升效率
LockSupport.unpark(node.thread);
//如果提前唤醒不满足条件,就会通过ReentrantLock自己的unlock方法,来唤醒AQS中的node
return true;
}
//回到park被挂起位置
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
long savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//调用ReentrantLock的竞争锁方法 重新竞争锁资源
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//这个又回到了ReentrantLock的了逻辑,竞争成功就替换head节点,不成功挂起线程
final boolean acquireQueued(final Node node, long arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
阻塞队列(Condition的一种应用场景)
阻塞队列利用了ReetrantLock,及其子下两个condition队列,NotFull存储生产者队列,NotEmpty存储消费者队列,实现消息的put和take的阻塞机制。
核心对象
- NotFull: 存储生产者线程的Condition阻塞队列,当Producer调用put方法发现已经超过了队列最大容量是,会将线程缓存到NotFull
- NotEmpty: 存储消费者线程的Condition阻塞队列,当Consumer调用take方法,发现队列里面没有数据,会将线程缓存到NotEmpty
- putIndex: 记录生产者最后一次put到阻塞队列的下标位置,当达到最大下标=>重置为0
- takeIndex: 记录消费者最后一次take那去数据的阻塞队列的下标位置,当达到最大下标=>重置为0
消息put到blockQueue里面,如果队列未满,加入到队列,同时putIndex++,当put到最大容量是,putIndex回到初始位置0;如果下次还有producer put消息,则将线程阻塞到NotFull的Condition队列
消费者从blockQueue中take拉取消息,如果队列中只有一个数据,消费完该数据之后,takeIndex回到初始位置0,如果还有消费者线程take消费,则线程阻塞到NotEmpty的Condition队列中。
示例代码
public class BlockQueueDemo {
public static void main(String[] args) {
ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10);
//消费者线程
new Thread(() -> {
try {
while (true) {
Thread.sleep(1000);
//如果线程空了 take方法会使线程挂起
String data = blockingQueue.take();
System.out.println("开始消费消息:" + data);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
//生产者线程
new Thread(() -> {
while (true) {
int count = 0;
try {
System.out.println("生产消息:" + (++count));
//如果队列满了 put方法会使当前线程挂起
blockingQueue.put(String.valueOf(count));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}

CountDownLatch
countDownLatch相当于提供一个阀门,在初始化的时候设置一个state=n,每次在执行countDownLatch.countDown()->n--;当n==0时,所有的调用countDownLatch.await();的方法就都会执行。
类图

核心对象
- CountDownLatch 类本身
- Sync CountDownLatch的内部类(不要混淆 ReentrantLock中也有一个Sync内部类)
- AbstractQueueSynchorized AQS队列里面 里面维护了双向链表和单向链表
代码示例
public class CountDownLachDemo{
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i=0;i<1000;i++) {
new Thread(() -> {
try {
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "运行");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"Thread_" + i).start();
}
System.out.println("3秒后开启阀门");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
}
}
核心流程
new CountDownLatch
//new CountDownLatch 传入的参数最终会设置到AQS的state
protected final void setState(int newState) {
state = newState;
}
await
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//tryAcquireShare 判断state是否==0,满足返回1 否则返回-1
if (tryAcquireShared(arg) < 0)
//加入到单向链表 阻塞线程
doAcquireSharedInterruptibly(arg);
}
//tryAcquireShare 判断state是否==0,满足返回1 否则返回-1
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//加入到单向链表阻塞线程
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
//加入双向链表 并将nextWaiter标记为Node.SHARED
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
//判断node的上一个节点是不是头节点
final Node p = node.predecessor();
if (p == head) {
//是重新判断state (getState() == 0) ? 1 : -1;
int r = tryAcquireShared(arg);
if (r >= 0) {
//state=0设置当前node为头节点,并唤醒下一个节点 next
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
//没有获取到节点则 执行parkAndCheckInterrupt
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//parkAndCheckInterrupt会返回是否被中断标识并复位 -> 此处如果有被中断则 响应中断抛出异常
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
countDown
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
//tryReleaseShared 如果state在执行减法操作后==0
//就会触发doReleaseSharedunpark阻塞的线程
if (tryReleaseShared(arg)) {
//unpark阻塞队列的线程
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
//如果本来就是0 说明已经执行过doReleaseShared 不需要重复执行 返回false
if (c == 0)
return false;
int nextc = c-1;
//减法操作后 结果==0 说明countDownlatch需要unpark在awaid方法阻塞的线程
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
重要方法唤醒AQS队列的线程
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
//唤醒head节点的下一个节点
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
//唤醒之后的逻辑
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
//唤醒后自旋进入方法判断 上一个节点是不是头节点
if (p == head) {
//是重新判断state (getState() == 0) ? 1 : -1; 判断是否已完全释放门栓锁
int r = tryAcquireShared(arg);
if (r >= 0) {
//state=0设置当前node为头节点,并唤醒下一个节点 next
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
//没有获取到节点则 执行parkAndCheckInterrupt
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
// !!!从这里开始唤醒之后的逻辑
//parkAndCheckInterrupt会返回是否被中断标识并复位 -> 此处如果有被中断则 响应中断抛出异常
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//再次调回doReleaseShared唤醒下一个节点
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
//将当前唤醒的节点设置为新的head节点
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
//拿到下一个节点 不为空就唤醒
Node s = node.next;
if (s == null || s.isShared())
//唤醒head节点的下一个节点
doReleaseShared();
}
}
//通过传递唤醒最终就唤醒了所有的线程

Semaphore
Semaphore 信号量,是限流常用的实现方式。类似于停车位,想像一下现在只有5个停车位,只能同时有5辆车停车,其他车需要等待释放信号量也就是车位空闲出来,才能停车。
public class SemaphoreDemo {
public static void main(String[] args) {
//建立信号量
Semaphore semaphore = new Semaphore(5);
for(int i=0;i<1000;i++){
new Thread(
() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "开始运行");
semaphore.release();
} , "Thread_" + i
).start();
}
}
}
Semaphore和CounDownLatch实现几乎一样,只是tryAcquireShared获取执行权限的方法不一样
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
//每次回用存量的信号量值 - 传入的需要获取值
int remaining = available - acquires;
//如果小于0 就阻塞进入if逻辑 如果>0说明有执行权限直接返回不处理
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
//这里由于是减法之后大于0才会触发setHeadAndPropagate
//所以它的传递唤醒,只能在state>0的情况下生效
//不会一直传递唤醒下去 这是和countDownLatch最大的区别
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
//state减法之后<0说明信号量值用完,需要等待其他线程释放信号,挂起线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

浙公网安备 33010602011771号