java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)

2025-09-19 23:43:37
Avatar for adminadmin

接着上面的例子,还是这三个工人,不过这一次,这三个工人自由了,老板不用检查他们任务了,他们三个合作建桥,有三个桩,每人打一个,同时打完之后才能一起搭桥(搭桥需要三人一起合作)。也就是说三个人都打完桩之后才能继续工作。

package LatchAndCyclicBarrier;

import java.util.concurrent.CyclicBarrier;

public class CycWork implements Runnable {

private CyclicBarrier cyclicBarrier ;

private String name ;

public CycWork(CyclicBarrier cyclicBarrier,String name)

{

this .name =name;

this .cyclicBarrier =cyclicBarrier;

}

@Override

public void run() {

// TODO Auto-generated method stub

System. out .println(name +"正在打桩,毕竟不轻松。。。。。" );

try {

Thread. sleep(5000);

System. out .println(name +"不容易,终于把桩打完了。。。。" );

cyclicBarrier .await();

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}

System. out .println(name +":其他逗b把桩都打完了,又得忙活了。。。" );

}

}

测试程序

package LatchAndCyclicBarrier;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class CycTest {

public static void main(String[] args)

{

ExecutorService executorpool=Executors. newFixedThreadPool(3);

CyclicBarrier cyclicBarrier= new CyclicBarrier(3);

CycWork work1= new CycWork(cyclicBarrier, "张三" );

CycWork work2= new CycWork(cyclicBarrier, "李四" );

CycWork work3= new CycWork(cyclicBarrier, "王五" );

executorpool.execute(work1);

executorpool.execute(work2);

executorpool.execute(work3);

executorpool.shutdown();

}

}

运行结果:

李四正在打桩,毕竟不轻松。。。。。

张三正在打桩,毕竟不轻松。。。。。

王五正在打桩,毕竟不轻松。。。。。

李四不容易,终于把桩打完了。。。。

张三不容易,终于把桩打完了。。。。

王五不容易,终于把桩打完了。。。。

王五:其他逗b把桩都打完了,又得忙活了。。。

李四:其他逗b把桩都打完了,又得忙活了。。。

张三:其他逗b把桩都打完了,又得忙活了。。。

CountDownlatch和CyclicBarrierde 源码部分

1、CountDownLatch中的两个关键方法

public void countDown() { //对计数器减一 表示有一个事件已经发生了

sync.releaseShared(1);

}

public void await() throws InterruptedException { //等到计数器为0

sync.acquireSharedInterruptibly(1);

}

await方法调用了AbstractQueuedSynchronizer中的acquireSharedInterruptibly

public final void acquireSharedInterruptibly (int arg)

throws InterruptedException {

if (Thread.interrupted())

throw new InterruptedException();

if (tryAcquireShared(arg) < 0)

doAcquireSharedInterruptibly(arg);

}

public final boolean releaseShared (int arg) {

if (tryReleaseShared(arg)) {

doReleaseShared();

return true ;

}

return false ;

}

protected boolean tryReleaseShared (int arg) {

throw new UnsupportedOperationException();

}

2、CyclicBarrier中的await()方法

public int await() throws InterruptedException, BrokenBarrierException {

try {

return dowait(false, 0L);

} catch (TimeoutException toe) {

throw new Error(toe); // cannot happen;

}

}

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) { // tripped

boolean 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 out

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();

}

}

上面dowait方法中有一个index,index=--count而count的值在源码中来自

count = parties;

提到 parties就不得不看看构造函数了

public CyclicBarrier(int parties) {

this(parties, null);

}

如上例子,我们构造了CyclicBarrier(3)那么此时的 count值为3,接着dowait源码,当index==0时,后面执行的

final Runnable command = barrierCommand;

其实是可以设置的,这个Runnable可以传进来,当我们希望所有线程都达到某一时刻之后,用什么线程执行接下来的工作,当没有传Runnable进来时,就继续执行(唤醒其他线程),否则就runnable.run()(唤醒其他线程之前执行)

Copyright © 2088 沙滩足球世界杯_足球世界杯中国 - pfw18.com All Rights Reserved.
友情链接