Java并发包:CountDownLatch和CyclicBarrier

本文深入介绍了Java并发包中两种重要工具:CountDownLatch和CyclicBarrier的使用方法与应用场景。CountDownLatch用于一个或多个线程等待一组操作完成,而CyclicBarrier则确保一组线程在继续执行前全部达到某个同步点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章译自:http://tutorials.jenkov.com/java-util-concurrent/index.html
抽空翻译了一下这个教程的文章,后面会陆续放出,如有不妥,请批评指正。
转自请注明出处。

CountDownLatch

java.util.concurrent.CountDownLatch是一种并发结构,它允许一个或者多个线程等待一个给定的操作集合完成。

CountDownLatch初始化时需要给定一个总数。这个总数将会随着调用countDown()方法每次递减。通过调用await()方法,线程将会等到这个总数变为0。调用await()方法会阻塞线程直到那个总数递减到0为止。

下面是一个简单的例子。Decrementer在CountDownLatch上调用了countDown()3次之后,Waiter将会释放。

CountDownLatch latch = new CountDownLatch(3);

Waiter      waiter      = new Waiter(latch);
Decrementer decrementer = new Decrementer(latch);

new Thread(waiter).start();
new Thread(decrementer).start();

Thread.sleep(4000);
public class Waiter implements Runnable{

    CountDownLatch latch = null;

    public Waiter(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Waiter Released");
    }
}
public class Decrementer implements Runnable {

    CountDownLatch latch = null;

    public Decrementer(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {

        try {
            Thread.sleep(1000);
            this.latch.countDown();

            Thread.sleep(1000);
            this.latch.countDown();

            Thread.sleep(1000);
            this.latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

添加一个客户端连接Zookeeper的例子。

/**
 * Created by charming on 2017/11/15.
 * 这里 CountDownLatch 用于停止(等待)主进程,直到客户端与ZooKeeper集合连接。
 * ZooKeeper集合通过监视器回调来回复连接状态。一旦客户端与ZooKeeper集合连接,监视器回调就会被调用,
 * 并且监视器回调函数调用CountDownLatch的countDown方法来释放锁,在主进程中await。
 */
public class ZooKeeperConnection {
    // declare zookeeper instance to access ZooKeeper ensemble
    private ZooKeeper zoo;
    final CountDownLatch connectedSignal = new CountDownLatch(1);

    public ZooKeeper connect(String host) throws IOException,InterruptedException {
        zoo = new ZooKeeper(host, 5000, new Watcher() {
            public void process(WatchedEvent event) {

                if (event.getState() == Event.KeeperState.SyncConnected) {
                    connectedSignal.countDown();
                }

            }
        });
        connectedSignal.await();
        return zoo;
    }

    // Method to disconnect from zookeeper server
    public void close() throws InterruptedException {
        zoo.close();
    }
}

CyclicBarrier

java.util.concurrent.CyclicBarrier类的同步机制可以通过某些算法实现同步线程的执行,换句话说,它就像一个屏障(或着说栏栅),在任何线程执行之前,所有线程必须在此处等着,直到所有线程都到达才执行。下面是图解:
这里写图片描述
所有的线程会在CyclicBarrier上调用await()方法相互等待,一旦N个线程正在CyclicBarrier上等待,所有的线程都会释放并且继续执行。

创建 CyclicBarrier

当你创建一个CyclicBarrier,你需要指定在它上面有多少个体线程同时等待,下面是如何创建一个CyclicBarrier:

CyclicBarrier barrier = new CyclicBarrier(2);

有2个线程在CyclicBarrier上等待,这两个线程就会释放。

在CyclicBarrier上等待

下面是一个线程如何在CyclicBarrier上等待:

barrier.await();

你也可以指定线程等待的时间。当等待的时间过了,即使不是所有指定的线程都在CyclicBarrier上等待,线程也会被释放。下面是如何指定超时时间:

barrier.await(10, TimeUnit.SECONDS);

等待的线程会在CyclicBarrier上等待直至:

  • 最后的线程达到
  • 线程被另一个线程中断(另一个线程调用interrupt()方法)
  • 另一个等待的线程被中断
  • 另一个等待的线程等待超时
  • 某些外部线程调用了CyclicBarrier.reset()方法
CyclicBarrier Action

CyclicBarrire支持一种栏栅行为,一但最后的线程达到时线程将会执行。Runnable的栅栏行为通过CyclicBarrier的构造函数传递,像下面这样:

Runnable      barrierAction = ... ;
CyclicBarrier barrier       = new CyclicBarrier(2, barrierAction);
CyclicBarrier示例

下面的代码展示如何使用CyclicBarrier:

Runnable barrier1Action = new Runnable() {
    public void run() {
        System.out.println("BarrierAction 1 executed ");
    }
};
Runnable barrier2Action = new Runnable() {
    public void run() {
        System.out.println("BarrierAction 2 executed ");
    }
};

CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);

CyclicBarrierRunnable barrierRunnable1 =
        new CyclicBarrierRunnable(barrier1, barrier2);

CyclicBarrierRunnable barrierRunnable2 =
        new CyclicBarrierRunnable(barrier1, barrier2);

new Thread(barrierRunnable1).start();
new Thread(barrierRunnable2).start();

下面是CyclicBarrier类:

public class CyclicBarrierRunnable implements Runnable{

    CyclicBarrier barrier1 = null;
    CyclicBarrier barrier2 = null;

    public CyclicBarrierRunnable(
            CyclicBarrier barrier1,
            CyclicBarrier barrier2) {

        this.barrier1 = barrier1;
        this.barrier2 = barrier2;
    }

    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() +
                                " waiting at barrier 1");
            this.barrier1.await();

            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() +
                                " waiting at barrier 2");
            this.barrier2.await();

            System.out.println(Thread.currentThread().getName() +
                                " done!");

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

下面是上面代码在控制台的输出结果,注意每次执行线程在控制台上打印的顺序也可能不一样。有时候可能是Thread-0先打印,有时候可能是Thread-1先打印。

Thread-0 waiting at barrier 1
Thread-1 waiting at barrier 1
BarrierAction 1 executed
Thread-1 waiting at barrier 2
Thread-0 waiting at barrier 2
BarrierAction 2 executed
Thread-0 done!
Thread-1 done!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值