`

java.util.concurrent包探秘(一)之CountDownLatch

    博客分类:
  • java
阅读更多

1. 类简介

    引用JDK1.6 API中的介绍:

    一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

    用给定的计数初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier

CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。

CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await

 

    这就是说,CountDownLatch可以用来管理一组相关的线程执行,只需在主线程中调用CountDownLatch 的await方法(一直阻塞),让各个线程调用countDown方法。当所有的线程都只需完countDown了,await也顺利返回,不再阻塞了。 在这样情况下尤其适用:将一个任务分成若干线程执行,等到所有线程执行完,再进行汇总处理。

 

2. 示例(参照其他博客,并做了些修改)
    下面我举一个非常简单的例子。假设我们要打印1-100,最后再输出“Ok“。1-100的打印顺序不要求统一,只需保证“Ok“是在最后出现即可。

    解决方案:我们定义一个CountDownLatch,然后开10个线程分别打印(n-1)*10+1至(n-1)*10+10。主线程中调用await 方法等待所有线程的执行完毕,每个线程执行完毕后都调用countDown方法。最后再await返回后打印“Ok”。

 

    具体代码如下:

package com.gw.concurrent;

import java.util.concurrent.CountDownLatch;

/**
 *@author zcc
 *@date  2013-7-24
 *@description CountDownLatch使用示例
 *@version 1.0.0
 */
public class TestCountDownLatch
{

     private static final int N = 10; 
     
        public static void main(String[] args) throws InterruptedException { 
            CountDownLatch doneSignal = new CountDownLatch(N); //线程计数信号
            CountDownLatch startSignal = new CountDownLatch(1);//开始执行信号 
     
            for (int i = 1; i <= N; i++) { 
                new Thread(new Worker(i, doneSignal, startSignal, "Thread"+i)).start();//线程启动了 
            } 
            System.out.println("begin------------"); 
            startSignal.countDown();//开始执行啦 ,startSignal每调用一次countDown,计数都减1,直到0
            doneSignal.await();//等待所有的线程执行完毕,即doneSignal计数变为0
            System.out.println("Ok"); 
     
        } 
     
        static class Worker implements Runnable { 
            private final CountDownLatch doneSignal; 
            private final CountDownLatch startSignal; 
            private int beginIndex; 
            private String name;
     
            Worker(int beginIndex, CountDownLatch doneSignal, 
                    CountDownLatch startSignal, String name) { 
                this.startSignal = startSignal; 
                this.beginIndex = beginIndex; 
                this.doneSignal = doneSignal; 
                this.name = name;
            } 
     
            public void run() { 
                try { 
                    startSignal.await(); //等待开始执行信号的发布 ,在startSignal计数等于0的时候开始执行
                    beginIndex = (beginIndex -1) * 10 + 1; 
                    for (int i = beginIndex; i < beginIndex + 10; i++) { 
                        System.out.println(this.name + "::"+ i); 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    doneSignal.countDown();  //doneSignal计数减1
                } 
            } 
        } 

}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics