CountDownLatch ,把一个工作分给5个人,5个线程都执行完了,调用countDown,给计数器减数,而主线程await,等数为零,主线程继续往下执行,即5条线程都完成才算工作完成。
内部很简单,还是继承AQS,把设置的数量赋值给state,countDown就减state,await想必挂起线程和解放线程。
CyclicBarrier 这么打比方,5个线程,每个人的工作分成两部分,完成第一部分后,需要确保5个人都完成了第一部分,大家才能各自进行第二部分。同时CyclicBarrier 可以设置一个主任务,在5个人的第一部分都执行完之后,这个主任务就会执行
CountDownLatch 是一个线程(例子中是主线程)等待其他线程执行完毕后,才能执行。
CyclicBarrier 是多个线程互相等待对方执行到指定的那一步,然后这些线程才能继续执行
一.CountDownLatch
1.例子
public class TestCountDown {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(4);
Work w1 = new Work(latch);
Work w2 = new Work(latch);
Work w3 = new Work(latch);
w1.start();
w2.start();
w3.start();
latch.await();
System.out.println("latch要等计数器为0,await方法才能释放");
}
static class Work extends Thread{
private CountDownLatch latch;
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"正在工作");
latch.countDown();
}
public Work(CountDownLatch latch) {
super();
this.latch = latch;
}
}
}
主线程只有等三个线程都执行完,计数器为零后,await方法才释放,才执行
如果改为CountDownLatch latch = new CountDownLatch(4);
会发现主线程一直堵塞,因为计数器永远无法到0
2.应用场景
开五个线程去上传或下载,只有五个线程都成功才算成功
3.源码
new CountDownLatch(4);数量其实是Sync的state
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 zero
for (;;) {
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);
}
countDown其实就是在对state减一,到0时就不能减了
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
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;
}
}
await应该是计算state是否=0,不等于就堵塞
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
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) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
二.CyclicBarrier
1.例子
public class TestCyclicBarrier {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3,new TotalTask());
Work w1 = new Work(barrier);
Work w2 = new Work(barrier);
Work w3 = new Work(barrier);
w1.start();w2.start();w3.start();
System.out.println("z主线程");
}
static class TotalTask extends Thread{
@Override
public void run() {
System.out.println("所有任务的第一部分都执行完,总任务就会执行");
}
}
static class Work extends Thread{
private CyclicBarrier barrier;
public Work(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行工作的第一部分");
try {
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行工作的第二部分");
}
}
}