CountDownLatch应用

来源:互联网 发布:mac os 10.12 原版 编辑:程序博客网 时间:2024/06/06 19:10

CountDownLatch是一个同步辅助类,犹如倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则处于等待状态,调用countDown()方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。

package com.thread;import java.util.concurrent.CountDownLatch;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** *  * @author Administrator *该程序用来模拟发送命令与执行命令,主线程代表指挥官,新建3个线程代表战士,战士一直等待着指挥官下达命令, *若指挥官没有下达命令,则战士们都必须等待。一旦命令下达,战士们都去执行自己的任务,指挥官处于等待状态,战士们任务执行完毕则报告给 *指挥官,指挥官则结束等待。 */public class CountdownLatchTest {    public static void main(String[] args) {        ExecutorService service = Executors.newCachedThreadPool(); //创建一个线程池        final CountDownLatch cdOrder = new CountDownLatch(1);//指挥官的命令,设置为1,指挥官一下达命令,则cutDown,变为0,战士们执行任务        final CountDownLatch cdAnswer = new CountDownLatch(3);//因为有三个战士,所以初始值为3,每一个战士执行任务完毕则cutDown一次,当三个都执行完毕,变为0,则指挥官停止等待。                for(int i=0;i<3;i++){            Runnable runnable = new Runnable(){                    public void run(){                    try {                        System.out.println("线程" + Thread.currentThread().getName() +                                 "正准备接受命令");                                                cdOrder.await(); //战士们都处于等待命令状态                        System.out.println("线程" + Thread.currentThread().getName() +                         "已接受命令");                                                        Thread.sleep((long)(Math.random()*10000));                            System.out.println("线程" + Thread.currentThread().getName() +                                 "回应命令处理结果");                                                cdAnswer.countDown(); //任务执行完毕,返回给指挥官,cdAnswer减1。                                        } catch (Exception e) {                        e.printStackTrace();                    }                                }            };            service.execute(runnable);//为线程池添加任务        }                try {            Thread.sleep((long)(Math.random()*10000));                    System.out.println("线程" + Thread.currentThread().getName() +                     "即将发布命令");                                    cdOrder.countDown(); //发送命令,cdOrder减1,处于等待的战士们停止等待转去执行任务。            System.out.println("线程" + Thread.currentThread().getName() +             "已发送命令,正在等待结果");                cdAnswer.await(); //命令发送后指挥官处于等待状态,一旦cdAnswer为0时停止等待继续往下执行            System.out.println("线程" + Thread.currentThread().getName() +             "已收到所有响应结果");            } catch (Exception e) {            e.printStackTrace();        }                        service.shutdown(); //任务结束,停止线程池的所有线程    }}

线程pool-1-thread-2正准备接受命令
线程pool-1-thread-3正准备接受命令
线程pool-1-thread-1正准备接受命令
线程main即将发布命令
线程pool-1-thread-2已接受命令
线程pool-1-thread-3已接受命令
线程pool-1-thread-1已接受命令
线程main已发送命令,正在等待结果
线程pool-1-thread-2回应命令处理结果
线程pool-1-thread-1回应命令处理结果
线程pool-1-thread-3回应命令处理结果
线程main已收到所有响应结果


java的concurrent包里面的CountDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。
      你可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。
      CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。
      举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:

package org.zapldy.concurrent;    import java.util.Random;  import java.util.concurrent.CountDownLatch;  import java.util.concurrent.TimeUnit;    public class Worker implements Runnable{            private CountDownLatch downLatch;      private String name;            public Worker(CountDownLatch downLatch, String name){          this.downLatch = downLatch;          this.name = name;      }            public void run() {          this.doWork();          try{              TimeUnit.SECONDS.sleep(new Random().nextInt(10));          }catch(InterruptedException ie){          }          System.out.println(this.name + "活干完了!");          this.downLatch.countDown();                }            private void doWork(){          System.out.println(this.name + "正在干活!");      }        }  
package org.zapldy.concurrent;    import java.util.concurrent.CountDownLatch;    public class Boss implements Runnable {        private CountDownLatch downLatch;            public Boss(CountDownLatch downLatch){          this.downLatch = downLatch;      }            public void run() {          System.out.println("老板正在等所有的工人干完活......");          try {              this.downLatch.await();          } catch (InterruptedException e) {          }          System.out.println("工人活都干完了,老板开始检查了!");      }    } 
package org.zapldy.concurrent;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CountDownLatchDemo {public static void main(String[] args) {ExecutorService executor = Executors.newCachedThreadPool();CountDownLatch latch = new CountDownLatch(3);Worker w1 = new Worker(latch,"张三");Worker w2 = new Worker(latch,"李四");Worker w3 = new Worker(latch,"王二");Boss boss = new Boss(latch);executor.execute(w3);executor.execute(w2);executor.execute(w1);executor.execute(boss);executor.shutdown();}}
当你运行CountDownLatchDemo这个对象的时候,你会发现是等所有的工人都干完了活,老板才来检查,下面是我本地机器上运行的一次结果,可以肯定的每次运行的结果可能与下面不一样,但老板检查永远是在后面的。

王二正在干活!
李四正在干活!
老板正在等所有的工人干完活......
张三正在干活!
张三活干完了!
王二活干完了!
李四活干完了!
工人活都干完了,老板开始检查了!



1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 植发的了毛囊炎怎么办 长得好看不上镜怎么办 鬓角的头发总翘怎么办 戴贞洁锁硬了怎么办 欠很多钱还不了怎么办 理财平台跑路了怎么办 联通4g信号不好怎么办 老年人耳朵嗡嗡响什么原因怎么办 单侧耳朵嗡嗡响怎么办 蚊子钻到耳朵里怎么办 小飞虫进耳朵里怎么办 耳朵里飞进去虫怎么办 耳朵里进虫子了怎么办 耳朵进虫子了怎么办啊 耳朵里进了蚊子怎么办 有虫子爬进耳朵怎么办 虫子死在耳朵里怎么办 早上起床口苦口臭怎么办 耳朵被耳屎堵了怎么办 油耳朵被堵住了怎么办 棉签掏耳朵堵了怎么办 耳朵被气堵住了怎么办 掏耳朵发炎了疼怎么办 掏耳朵掏深了疼怎么办 耳朵里进了虫子怎么办? 耳朵里飞进小虫怎么办 一只耳朵听力差怎么办 62岁耳朵有点聋怎么办 一支耳朵有点聋怎么办 80岁老人耳朵聋怎么办 被nlp课程洗脑了怎么办 手上张了个鸡眼怎么办 手上长了个鸡眼怎么办 6岁儿童手指脱皮怎么办 手指骨折后关节僵硬怎么办 手指外伤后关节肿大僵硬怎么办 胳膊骨折了手肿怎么办 耳朵被肘了耳鸣怎么办 耳朵鼓膜外显的怎么办 耳膜破了怎么办为好 耳朵的鼓膜破了怎么办