Semaphore
允许多个线程同时访问。Syn类实现共享模式。
构造函数
permits:允许访问最大线程数
fair:指定是否是公平锁,默认false。
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
获取锁(非公平锁)
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
sync父类AbstractQueuedSynchronizer的方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);//将节点加入等待队列(AbstractQueuedSynchronizer类方法)
}
调用非公平锁重写的tryAcquireShared方法
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
调用父类syn类nonfairTryAcquireShared方法
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
//获取当前可获取锁线程数
int available = getState();
//加算新的线程数
int remaining = available - acquires;
//如果无法获取或者CAS设置state成功,返回state
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
释放锁(非公平锁)
public void release() {
sync.releaseShared(1);
}
调用sync父类AbstractQueuedSynchronizer的方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();//删除节点并唤醒其他线程
return true;
}
return false;
}
调用非公平锁重写的tryReleaseShared方法
protected final boolean tryReleaseShared(int releases) {
for (;;) {
//获取当前允许线程数
int current = getState();
//计算新的state
int next = current + releases;
if (next < current) // 溢出
throw new Error("Maximum permit count exceeded");
//CAS设置state
if (compareAndSetState(current, next))
return true;
}
}
获取剩余所有数量
final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
CountDownLatch
允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
CountDownLatch通过一个计数器记录线程的数量,每个线程调用countDown方法后计数器会减一,当计数器为0时,等待的线程(即调用countDownLatch.await方法的线程)会被唤起。Syn类实现共享模式。
构造方法
指定计数器大小
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
await方法
调用此方法的线程会被阻塞,直到计数器为0或线程被中断
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
sync父类AbstractQueuedSynchronizer的acquireSharedInterruptibly方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);//将节点加入等待队列,将节点状态设置为共享
//此方法会自旋,当队列中只有一个节点等待时,会等到state=0返回,当队列中有其他节点等待时,将前节点设为SIGNAL状态,再阻塞自己
}
sync类重写tryAcquireShared方法
//state=0 返回1(成功),否则返回-1
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
countDown方法
public void countDown() {
sync.releaseShared(1);
}
sync父类AbstractQueuedSynchronizer的releaseShared方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();//唤醒队列中等待的线程(包括后继节点)
return true;
}
return false;
}
sync类重写tryReleaseShared方法
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;
//CAS修改计数器
if (compareAndSetState(c, nextc))
//当计数器不为0时返回false,不会唤醒队列中的线程
return nextc == 0;
}
}
使用场景:
1.某个线程调用await后等待n个线程执行完毕(new CountDownLatch(n))
2.多线程共享一个countDownLatch(new CountDownLatch(1)),n个线程调用await方法,主线程调用countDown(),n个线程同时被唤醒
CyclicBarrier
一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有阻塞的线程被唤醒。
数据结构
Generation代表每一轮Cyclibarrier的运行状况
private static class Generation {
Generation() {}
boolean broken; //是否挂掉,默认为false
}
属性
private final ReentrantLock lock = new ReentrantLock();
private final Condition trip = lock.newCondition();
private final int parties;
private final Runnable barrierCommand;
private Generation generation = new Generation();
private int count;
构造方法
parties:表示线程数
barrierAction:所有线程都到达barrier时执行,可以为null
count:表示还未到达barrier的线程数,可以重置为parities
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
await方法
await() 调用dowait(time)
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
//当前Generation挂掉
if (g.broken)
throw new BrokenBarrierException();
//线程中断,重置count
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
//计算当前剩余线程数
int index = --count;
//到达barrier
if (index == 0) {
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
//开启下一轮
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
//当前没有达到barrier,自旋
for (;;) {
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();
}
}
CountDownLatch与CyclicBarrier
1.CountDownLatch只能使用一次,CyclicBarrier可以多次使用
2.CountDownLatch减计数,CyclicBarrier加计数
3.CountDownLatch是一个或多个线程等其他线程完成后再执行,CyclicBarrier是多个线程互相等待到同步点再一起执行。