• 多线程分配线程的实现方案:CountDownLatch类


    需求:假如我们本地有4个文件需要解析,每个文件的内容为20万行。为了提高效率我们要创建4个线程进行处理。等4个线程处理完,要在文件日志表中记录处理状态。

    一般的的解决方法是使用join,join用于让当前执行线程等待join线程执行结束。其实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远wait。直到join线程中止后,线程的this.notifyAll会被调用。

    但是DK1.5之后的并发包中提供的CountDownLatch也可以实现join的这个功能,并且比join的功能更多。

     1 public class CountDownLatchTest {
     2 
     3     static CountDownLatch c = new CountDownLatch(4);
     4 /**线程记录数,当线程开始调用时主线程阻塞,每当一个线程结束时调用countDown()方法,线程记录数减一,当线程记录数为0时,主线程恢复调用。***/
     5 
     6     public static void main(String[] args) throws InterruptedException {
     7         new Thread(new Runnable() {
     8             @Override
     9             public void run() {
    10                 System.out.println(1);
    11                 c.countDown();//记录数减一,3
    12                 System.out.println(2);
    13                 c.countDown();//记录数减一,2
    14                                 System.out.println(3);
    15                 c.countDown();//记录数减一,1
    16                 System.out.println(4);
    17                 c.countDown();//记录数减一,0
    18             }
    19         }).start();
    20 
    21         c.await();
    22         System.out.println("主线程调用");//开始调用日志记录
    23     }
    24 
    25 }                    

    CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。

    当我们调用一次CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await会阻塞当前线程,直到N变成零。由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,你只需要把这个CountDownLatch的引用传递到线程里。

     1     /**
     2      * 单个文件处理入库
     3      * @author yanjp
     4      *
     5      */
     6     class Worker extends Thread{
     7         private DyFile dyFile;
     8         private CountDownLatch ct;
     9         private AnalyzeFileService analyzeFileService;
    10         public Worker(AnalyzeFileService analyzeFileService ,DyFile dyFile,CountDownLatch ct){
    11             this.dyFile=dyFile;
    12             this.ct=ct;
    13             this.analyzeFileService=analyzeFileService;
    14         }
    15         @Override
    16         public void run() {
    17             // TODO Auto-generated method stub
    18             try {
    19                 logger.info("begin入库处理文件:"+dyFile.getFileName());
    20                 //合适的处理器,处理文件.
    21                 analyzeFileService.analyze(dyFile);
    22                 logger.info("end入库处理文件:"+dyFile.getFileName());
    23             } catch (Exception e) {
    24                 // TODO Auto-generated catch block
    25                 logger.error("单个文件入库处理异常",e);
    26             }finally{
    27                 //完成一件任务
    28                 ct.countDown();
    29             }
    30         }
    31         
    32     }

    如果有某个解析sheet的线程处理的比较慢,我们不可能让主线程一直等待,所以我们可以使用另外一个带指定时间的await方法,await(long time, TimeUnit unit): 这个方法等待特定时间后,就会不再阻塞当前线程。join也有类似的方法。

    注意:计数器必须大于等于0,只是等于0时候,计数器就是零,调用await方法时不会阻塞当前线程。CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值。一个线程调用countDown方法 happen-before 另外一个线程调用await方法。

     CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。

    参考:

    http://ifeve.com/talk-concurrency-countdownlatch/

  • 相关阅读:
    POJ 2778 DNA Sequence(AC自动机+矩阵)
    Challenge & Growth —— 从这里开始
    京东云
    [Done] Codeforces Round #562 (Div. 2) 题解
    HDU 3486 Interviewe
    Codeforces Round #529 (Div. 3) 题解
    Wannafly 挑战赛 19 参考题解
    第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 题解
    2018年长沙理工大学第十三届程序设计竞赛 题解
    POJ 3017 Cut the Sequence
  • 原文地址:https://www.cnblogs.com/0mbiubiu/p/5337005.html
Copyright © 2020-2023  润新知