当前位置: 代码迷 >> 综合 >> 深度解析:CountDownLatch、CyclicBarrier、Semaphore基本原理
  详细解决方案

深度解析:CountDownLatch、CyclicBarrier、Semaphore基本原理

热度:98   发布时间:2023-11-22 01:38:09.0

CountDownLatch、CyclicBarrier、Semaphore都是基于AQS实现的同步组件。

CountDownLatch原理:

CountDownLatch初始化的时候需要指定一个初始值,调用了CountDownLatch的await方法的线程就会处于阻塞状态,会将阻塞的线程生成一个node节点放进AQS的同步队列中,每个线程在调用CountDownLatch的countDown方法,计数器就会减一直到state的值减到0的时候,才会唤醒同步队列中头结点下一个节点的线程,然后依次唤醒。

源码:


package java.util.concurrent;
import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.*;public class CountDownLatch {/*** Synchronization control For CountDownLatch.* Uses AQS state to represent count.*/private static final class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = 4982264981922014374L;Sync(int count) {setState(count);}int getCount() {return getState();}protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;}protected boolean tryReleaseShared(int releases) {// Decrement count; signal when transition to zerofor (;;) {int c = getState();if (c == 0)return false;int nextc = c-1;if (compareAndSetState(c, nextc))return nextc == 0;}}}private final Sync sync;public CountDownLatch(int count) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = new Sync(count);}public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public boolean await(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));}public void countDown() {sync.releaseShared(1);}public long getCount() {return sync.getCount();}public String toString() {return super.toString() + "[Count = " + sync.getCount() + "]";}
}

CyclicBarrier原理:

CyclicBarrier与CountDownLatch不同的是,它更像是一个屏障,直到线程等待的个数到达了一定数目之后才会唤醒所有线程一起执行。CyclicBarrier是通过ReentrantLock和Condition来实现的,它有两个构造函数,一个是在初始化的时候设置一个初始值,另一个是设置一个初始值和一个线程任务。它允许一组线程相互等待,直到到达某个屏障点。每次调用await方法的时候都会将CyclicBarrier的计数器减一,直到计数器减到零之后,就会唤醒所有处于等待队列当中的线程一起继续执行。它内部还有一个Generation类,记录线程属于哪一代的,如果计数器减为零,同一代的线程就会被唤醒,Generation就会更新换代。

源码:

package java.util.concurrent;
import java.util.concurrent.locks.*;public class CyclicBarrier {private static class Generation {boolean broken = false;}/** The lock for guarding barrier entry */private final ReentrantLock lock = new ReentrantLock();/** Condition to wait on until tripped */private final Condition trip = lock.newCondition();/** The number of parties */private final int parties;/* The command to run when tripped */private final Runnable barrierCommand;/** The current generation */private Generation generation = new Generation();/*** Number of parties still waiting. Counts down from parties to 0* on each generation.  It is reset to parties on each new* generation or when broken.*/private int count;/*** Updates state on barrier trip and wakes up everyone.* Called only while holding lock.*/private void nextGeneration() {// signal completion of last generationtrip.signalAll();// set up next generationcount = parties;generation = new Generation();}/*** Sets current barrier generation as broken and wakes up everyone.* Called only while holding lock.*/private void breakBarrier() {generation.broken = true;count = parties;trip.signalAll();}/*** Main barrier code, covering the various policies.*/private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException,TimeoutException {final ReentrantLock lock = this.lock;lock.lock();try {final Generation g = generation;if (g.broken)throw new BrokenBarrierException();if (Thread.interrupted()) {breakBarrier();throw new InterruptedException();}int index = --count;if (index == 0) {  // trippedboolean ranAction = false;try {final Runnable command = barrierCommand;if (command != null)command.run();ranAction = true;nextGeneration();return 0;} finally {if (!ranAction)breakBarrier();}}// loop until tripped, broken, interrupted, or timed outfor (;;) {try {if (!timed)trip.await();else if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {if (g == generation && ! g.broken) {breakBarrier();throw ie;} else {// We're about to finish waiting even if we had not// been interrupted, so this interrupt is deemed to// "belong" to subsequent execution.Thread.currentThread().interrupt();}}if (g.broken)throw new BrokenBarrierException();if (g != generation)return index;if (timed && nanos <= 0L) {breakBarrier();throw new TimeoutException();}}} finally {lock.unlock();}}public CyclicBarrier(int parties, Runnable barrierAction) {if (parties <= 0) throw new IllegalArgumentException();this.parties = parties;this.count = parties;this.barrierCommand = barrierAction;}public CyclicBarrier(int parties) {this(parties, null);}/*** Returns the number of parties required to trip this barrier.** @return the number of parties required to trip this barrier*/public int getParties() {return parties;}public int await() throws InterruptedException, BrokenBarrierException {try {return dowait(false, 0L);} catch (TimeoutException toe) {throw new Error(toe); // cannot happen;}}public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {return dowait(true, unit.toNanos(timeout));}/*** Queries if this barrier is in a broken state.** @return {@code true} if one or more parties broke out of this*         barrier due to interruption or timeout since*         construction or the last reset, or a barrier action*         failed due to an exception; {@code false} otherwise.*/public boolean isBroken() {final ReentrantLock lock = this.lock;lock.lock();try {return generation.broken;} finally {lock.unlock();}}public void reset() {final ReentrantLock lock = this.lock;lock.lock();try {breakBarrier();   // break the current generationnextGeneration(); // start a new generation} finally {lock.unlock();}}/*** Returns the number of parties currently waiting at the barrier.* This method is primarily useful for debugging and assertions.** @return the number of parties currently blocked in {@link #await}*/public int getNumberWaiting() {final ReentrantLock lock = this.lock;lock.lock();try {return parties - count;} finally {lock.unlock();}}
}

3、Semaphore:

Semaphore是一个基于计数器的信号量,初始化的时候可以设定一个阈值,多个线程竞争获取许可信号,做自己的申请后归还许可信号。如果许可信号达到了阈值之后,再来获取许可信号的线程将会被阻塞,直到有线程归还许可信号为止。Semaphore有两种模式,公平模式和非公平模式,公平模式就是调用acquire的顺序就是获取许可信号的顺序,遵循FIFO,而非公平就是抢占式的。

源码:

public class Semaphore implements java.io.Serializable {private final Sync sync;public Semaphore(int permits) {sync = new NonfairSync(permits); // 公平竞争,sync的锁状态(锁计数)state = permits}public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits); // 公平竞争 || 非公平竞争}public void acquire() throws InterruptedException; // acquire(1)public void acquire(int permits) throws InterruptedException { // permits必须>=0if (permits < 0) throw new IllegalArgumentException();sync.acquireSharedInterruptibly(permits);}public void acquireUninterruptibly(); // acquireUninterruptibly(1)public void acquireUninterruptibly(int permits) { // permits必须>=0if (permits < 0) throw new IllegalArgumentException();sync.acquireShared(permits);}public boolean tryAcquire(); // tryAcquire(1)public boolean tryAcquire(int permits) { // permits必须>=0if (permits < 0) throw new IllegalArgumentException();return sync.nonfairTryAcquireShared(permits) >= 0;}public boolean tryAcquire(long timeout, TimeUnit unit); // tryAcquire(1, timeout, unit)public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { // permits必须>=0if (permits < 0) throw new IllegalArgumentException();return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));}public void release(); // release(1)public void release(int permits) { // permits必须>=0if (permits < 0) throw new IllegalArgumentException();sync.releaseShared(permits);}... ...
}
abstract static class Sync extends AbstractQueuedSynchronizer {Sync(int permits) {setState(permits);}final int nonfairTryAcquireShared(int acquires) { // 尝试非公平取锁for (;;) {// CAS(state)失败将回到此处int available = getState();                                                      /*记录state*/int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining)) //remaining >= 0时/*CAS设置state -= acquires*/return remaining; // remaining < 0:SyncQueue中排队}}protected final boolean tryReleaseShared(int releases) {for (;;) {// CAS(state)失败将回到此处int current = getState();               /*记录state*/int next = current + releases;if (next < current) throw new Error("Maximum permit count exceeded");if (compareAndSetState(current, next)) /*CAS设置state += releases*/return true;}}... ...
}static final class NonfairSync extends Sync {NonfairSync(int permits) {super(permits);}protected int tryAcquireShared(int acquires) { // 尝试非公平取锁return nonfairTryAcquireShared(acquires);}
}static final class FairSync extends Sync {FairSync(int permits) {super(permits);}protected int tryAcquireShared(int acquires) { // 尝试公平取锁for (;;) {// CAS(state)失败将回到此处if (hasQueuedPredecessors()) // SyncQueue不为空 && SyncQueue中下个待唤醒节点非当前线程所在节点return -1; // int available = getState();                                                      /*记录state*/int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining)) //remaining >= 0时/*CAS设置state -= acquires*/return remaining;}}
}
  相关解决方案