浅谈CountDownLatch类

浅谈CountDownLatch类

CountDownLatch是JDK1.5引入的解决并发问题的新类,在java.util.coucurrent包下,下面先结合JDK中的注释介绍这个类以及类中常用的方法!

1-类的注释

提取JDK中类的注释如下:

A synchronization aid that allows one ormore threads to wait until a set of operations being performed in other threadscompletes.

A CountDownLatch is initialized with a given count.The await methods blockuntil the current count reaches zero due to invocations of the countdown method,after which all waiting threads are released and any subsequent invocations of awaitreturn immediately.  This is a one-shotphenomenon the count cannot be reset.  Ifyou need a version that resets the count, consider using a CyclicBarrier.A CountDownLatchis a versatile synchronization tool and can be used for a number ofpurposes.  A CountDownLatch initialized witha count of one serves as a simple on/off latch, or gate: all threads invoking awaitwait at the gate until it is opened by a thread invoking countDown. A CountDownLatchinitialized to N can be used to make one thread wait until N threads have completedsome action, or some action has been completed N times.

下面尝试翻译下上述内容,理解了上述的内容意思就大概可以明白CountDownLatch设计的意图:

CountDownLatch是一个同步辅助工具,用于使一个或多个线程等待(即阻塞)知道一组在其他线程中的任务结束。

CountDownLatch必须用给定的count(一个int类型的大于等于0的值)进行初始化。调用await方法将使线程阻塞,直到当前计数(count值)由于countdown方法的调用而达到零,此后所有等待的线程被释放并且任何后续调用await方法也会立即返回。CountDownLatch被设计为只触发一次,即Count值在运行过程中无法重置。如果需要重置计数的版本,可以考虑使用CyclicBarrier.

CountDownLatch是一种通用的同步工具。 CountDownLatch可以被认为是一个简单的on/off锁存器或门:所有线程调用await方法等待开关打开,直到countDown方法被调用打开开关为止。 创建一个CountDownLatch,指定count的值为N,那么这个CountDownLatch对象可以让一个线程等待其他N个线程结束(调用countDown方法即认为结束),或者调用了这个CountDownLatch的countDown方法N次。

2-方法的注释

1-构造器


构造器方法,必须指定count值,且count值不能小于0,注释的意思:创建CountDownLatch对象时需指定count值,count值即当前线程从调用await方法时处于阻塞状态转换到就绪状态时countDown方法必须调用的次数!

2-await方法

await方法使当前线程等待直到count值为0,或者当前线程被打断!如果当前的count值为0,那么await方法直接返回,当前线程不会阻塞!如果当前的count值大于0,那么当前线程阻塞(线程调度机制无法给当前线程分配CPU时间片),直到以下两种情况任意一种发生为止:

1-count值通过countDown方法的调用达到0

2-    其他线程打断了当前线程

3-   countDown方法

当前的count值减一,如果count值为0则释放所有等待的线程!如果当前count值大于0,则减一,如果count值为0,则所有等待的线程对于线程调度机制来说都是活跃的了!

3-代码说话

创建一个模拟执行任务后调用countDown的任务,代码如下:

class TaskPortion implements Runnable {

    private static int counter = 0;

    //编号
    private final int id = counter++;

    private static Random random = new Random(47);

    //通过构造器指定CountDownLatch对象
    private final CountDownLatch latch;

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

    @Override
    public void run() {
        try {
            //模拟任务的执行
            doWork();
            //任务执行完,将CountDownLatch对象的count值减一
            latch.countDown();
            //打印当前的count值
            System.out.println("Count of Latch:" + latch.getCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void doWork() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));
        System.out.println(this + " completed!");
    }

    public String toString() {
        return String.format("%1$-3d", id);
    }
}

创建一个调用CountDownLatch的await方法的任务:

/**
 * 等待任务
 */
class WaitingTask implements Runnable {

    private static int counter = 0;

    //编号
    private final int id = counter++;

    //通过构造器指定CountDownLatch对象
    private final CountDownLatch latch;

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

    @Override
    public void run() {
        try {
            //如果count>0阻塞,count=0直接执行
            latch.await();
            System.out.println("Count of Latch:" + latch.getCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

创建测试类,代码如下:

public class CountDownLatchDemo {

    private static int COUNT = 5;
    private static int LOOP = 4;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //创建一个count=5的CountDownLatch对象
        CountDownLatch latch = new CountDownLatch(COUNT);
        //10个WaitingTask阻塞
        for (int i = 0; i < 10; i++) {
            executorService.execute(new WaitingTask(latch));
        }
        /**
         * 如果LOOP<COUNT,latch的countDown方法只会调用4次,程序会阻塞
         */
        for (int i = 0; i < LOOP; i++) {
            executorService.execute(new TaskPortion(latch));
        }
        System.out.println("Latched all tasks!");
        executorService.shutdown();
    }

}

在测试代码中,首先初始化了一个CountDownLatch对象,其count值为COUNT,然后在线程池中添加了10条调用await方法的任务,10条任务阻塞,然后在线程池中添加了LOOP条调用了CountDownLatch实例的countDown方法的任务,每执行一个任务CountDownLatch对象的count值减一。可知如果LOOP<COUNT那么CountDownLatch对象的count值永远不会为0,那么程序10条任务就会一直等待,程序就一直阻塞!反之,如果LOOP>=COUNT,那么CountDownLatch实例的count值就会变成0,从而10条阻塞的任务就会释放!

当把测试代码中的LOOP改成5后,再次执行,打印结果如下:

Latched all tasks!
1   completed!
Count of Latch:4
2   completed!
Count of Latch:3
4   completed!
Count of Latch:2
0   completed!
Count of Latch:1
3   completed!
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值