一. CountDownLatch

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

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

CountDownLatch的主要方法:

                            方法名称                                       方法作用
public CountDownLatch(int count) 构造器参数指定了计数的次数,即有几个独立的任务
public void CountDown() 当前线程调用此方法,计数减一,即其中一个任务完成
public void await() 当前线程调用此方法会一直被阻塞,直到计数为0,即所有子任务都完成了。
   1: package com.wbl.test.thread.countDownLatch;

   2:  

   3: import java.text.SimpleDateFormat;

   4: import java.util.Date;

   5: import java.util.concurrent.CountDownLatch;

   6:  

   7: /**

   8:  * Created with Simple_love

   9:  * Date: 2016/3/19.

  10:  * Time: 16:06

  11:  */

  12: public class CountDownLatchDemo {


13:     final static SimpleDateFormat

sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  14:  

  15:         public static void main(String[] args) throws InterruptedException {

  16:                 CountDownLatch countDownLatch = new CountDownLatch(2);    //两个工人协同工作

  17:                 Worker worker1 = new Worker("work1",5000,countDownLatch);

  18:                 Worker worker2 = new Worker("work2",8000,countDownLatch);

  19:                 worker1.start();

  20:                 worker2.start();

  21:                 countDownLatch.await();   //等待所有的工人结束

  22:                 System.out.println("all work done at " + sdf.format(new Date()));

  23:         }

  24:  

  25:         static class Worker extends Thread{

  26:                 String name;

  27:                 int workTime;

  28:                 CountDownLatch countDownLatch;

  29:                 public Worker(String name,int workTime,CountDownLatch countDownLatch){

  30:                         this.name = name;

  31:                         this.workTime = workTime;

  32:                         this.countDownLatch = countDownLatch;

  33:                 }

  34:  

  35:                 public void doWork(){

  36:                         try {

  37:                                 Thread.sleep(workTime);

  38:                         }catch (InterruptedException e){

  39:                                 e.printStackTrace();

  40:                         }

  41:                 }

  42:  

  43:                 @Override

  44:                 public void run() {

  45:                         System.out.println("Worker " + name + " do work begin at " + sdf.format(new Date()));

  46:                         doWork();//工作了

  47:                        System.out.println("Worker "+name+" do work complete at "+sdf.format(new Date()));

  48:                        countDownLatch.countDown();//工人完成工作,计数器减一

  49:  

  50:                 }

  51:         }

  52: }

CountDownLatch被设计为只触发一次,计数值不能被重置。一旦计数器的值初始后,唯一可以修改它的方法就是之前用的 countDown() 方法。当计数器到达0时, 全部调用 await() 方法会立刻返回,接下来任何countDown() 方法的调用都将不会造成任何影响。

二. CyclicBarrier

字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

CyclicBarrier的主要方法

                            方法名称                                       方法作用
public CyclicBarrier(int): 构造器参数指定线程的个数,即有几个互相等待的任务
public void CyclicBarrier(int,Runnable):   当一组的线程全都到达某个状态后,开始执行Runnable对象
public void await() 某个线程到达barrier状态

CyclicBarrier的应用场景:在某种需求中,比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候,就可以选择CyclicBarrier了。

实例分析:我们需要统计全国的业务数据。其中各省的数据库是独立的,也就是说按省分库。并且统计的数据量很大,统计过程也比较慢。为了提高性能,快速计算。我们采取并发的方式,多个线程同时计算各省数据,最后再汇总统计。在这里CyclicBarrier就非常有用。

   1: /**  

   2: * 各省数据独立,分库存偖。为了提高计算性能,统计时采用每个省开一个线程先计算单省结果,最后汇总。  

   3: *   

   4: * @author guangbo email:weigbo@163.com  

   5: *   

   6: */  

   7: public class Total {   

   8:   

   9:    // private ConcurrentHashMap result = new ConcurrentHashMap();   

  10:   

  11:    public static void main(String[] args) {   

  12:        TotalService totalService = new TotalServiceImpl();   

  13:         CyclicBarrier barrier = new CyclicBarrier(5,   

  14:                 new TotalTask(totalService));   

  15:   

  16:         // 实际系统是查出所有省编码code的列表,然后循环,每个code生成一个线程。   

  17:         new BillTask(new BillServiceImpl(), barrier, "北京").start();   

  18:         new BillTask(new BillServiceImpl(), barrier, "上海").start();   

  19:         new BillTask(new BillServiceImpl(), barrier, "广西").start();   

  20:         new BillTask(new BillServiceImpl(), barrier, "四川").start();   

  21:         new BillTask(new BillServiceImpl(), barrier, "黑龙江").start();    

  22:    }   

  23: }   

  24:   

  25: /**  

  26:  * 主任务:汇总任务  

  27:  */  

  28: class TotalTask implements Runnable {   

  29:     private TotalService totalService;   

  30:   

  31:     TotalTask(TotalService totalService) {   

  32:         this.totalService = totalService;   

  33:     }   

  34:   

  35:     public void run() {   

  36:         // 读取内存中各省的数据汇总,过程略。   

  37:         totalService.count();   

  38:         System.out.println("=======================================");   

  39:         System.out.println("开始全国汇总");   

  40:     }   

  41: }   

  42:   

  43: /**  

  44:  * 子任务:计费任务  

  45:  */  

  46: class BillTask extends Thread {   

  47:     // 计费服务   

  48:     private BillService billService;   

  49:     private CyclicBarrier barrier;   

  50:     // 代码,按省代码分类,各省数据库独立。   

  51:     private String code;   

  52:   

  53:     BillTask(BillService billService, CyclicBarrier barrier, String code) {   

  54:         this.billService = billService;   

  55:        this.barrier = barrier;   

  56:         this.code = code;   

  57:     }   

  58:   

  59:     public void run() {   

  60:         System.out.println("开始计算--" + code + "省--数据!");   

  61:         billService.bill(code);   

  62:         // 把bill方法结果存入内存,如ConcurrentHashMap,vector等,代码略   

  63:         System.out.println(code + "省已经计算完成,并通知汇总Service!");   

  64:         try {   

  65:             // 通知barrier已经完成   

  66:             barrier.await();   

  67:         } catch (InterruptedException e) {   

  68:             e.printStackTrace();   

  69:         } catch (BrokenBarrierException e) {   

  70:             e.printStackTrace();   

  71:         }   

  72:     }   

  73:   

  74: }  

CountDownLatch和CyclicBarrier的区别

CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

三. DelayQueue

DelayQueue类的主要作用:是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。

Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序。

(1) 实例场景

模拟一个考试的日子,考试时间为120分钟,30分钟后才可交卷,当时间到了,或学生都交完卷了考试结束。

这个场景中几个点需要注意:

  1. 考试时间为120分钟,30分钟后才可交卷,初始化考生完成试卷时间最小应为30分钟

  2. 对于能够在120分钟内交卷的考生,如何实现这些考生交卷
  3. 对于120分钟内没有完成考试的考生,在120分钟考试时间到后需要让他们强制交卷
  4. 在所有的考生都交完卷后,需要将控制线程关闭

实现思想:用DelayQueue存储考生(Student类),每一个考生都有自己的名字和完成试卷的时间,Teacher线程对DelayQueue进行监控,收取完成试卷小于120分钟的学生的试卷。当考试时间120分钟到时,先关闭Teacher线程,然后强制DelayQueue中还存在的考生交卷。每一个考生交卷都会进行一次countDownLatch.countDown(),当countDownLatch.await()不再阻塞说明所有考生都交完卷了,而后结束考试。

   1: package com.wbl.test.thread.delayQueue;

   2:  

   3: import java.util.Iterator;

   4: import java.util.Random;

   5: import java.util.concurrent.CountDownLatch;

   6: import java.util.concurrent.DelayQueue;

   7: import java.util.concurrent.Delayed;

   8: import java.util.concurrent.TimeUnit;

   9:  

  10: /**

  11:  * Created with Simple_love

  12:  * Date: 2016/3/19.

  13:  * Time: 14:29

  14:  */

  15: public class Exam {

  16:         public static void main(String[] args) throws InterruptedException {

  17:                 int count = 20;

  18:                 DelayQueue<Student> students = new DelayQueue<>();

  19:                 Random random = new Random();

  20:                 CountDownLatch countDownLatch = new CountDownLatch(count+1);

  21:                 for (int i = 1; i <= 20; i++)

  22:                         students.add(new Student("student" + i,30+random.nextInt(120),countDownLatch));

  23:                 Thread teacherThread = new Thread(new Teacher(students));

  24:                 students.add(new EndExam(students,120,countDownLatch,teacherThread));

  25:                 teacherThread.start();

  26:                 countDownLatch.await();

  27:                 System.out.println(" 考试时间到,全部交卷!");

  28:         }

  29: }

  30: class Student implements Runnable,Delayed{

  31:         private String name;

  32:         private long workTime; //考试时间

  33:         private long submitTime; //交卷时间

  34:         private boolean isForce = false;

  35:         private CountDownLatch countDownLatch;

  36:  

  37:         public Student() {

  38:         }

  39:  

  40:         public Student(String name, long workTime,CountDownLatch countDownLatch) {

  41:                 this.name = name;

  42:                 this.workTime = workTime;

  43:                 this.submitTime = TimeUnit.NANOSECONDS.convert(workTime,TimeUnit.NANOSECONDS) + System.nanoTime();

  44:                 this.countDownLatch = countDownLatch;

  45:         }

  46:  

  47:         @Override

  48:         public long getDelay(TimeUnit unit) {

  49:                 return unit.convert(submitTime-System.nanoTime(),TimeUnit.NANOSECONDS);

  50:         }

  51:  

  52:         @Override

  53:         public int compareTo(Delayed o) {

  54:                 if (o == null || ! (o instanceof Student))

  55:                         return 1;

  56:                 if (o == this)

  57:                         return 0;

  58:                 Student temp = (Student)o;

  59:                 if (this.workTime > temp.workTime)

  60:                         return 1;

  61:                 else if (this.workTime == temp.workTime)

  62:                         return 0;

  63:                 else

  64:                         return -1;

  65:         }

  66:  

  67:         @Override

  68:         public void run() {

  69:                 if (isForce) {

  70:                         System.out.println(name + " 交卷, 希望用时" + workTime + "分钟"+" ,实际用时 120分钟" );

  71:                 }else {

  72:                         System.out.println(name + " 交卷, 希望用时" + workTime + "分钟"+" ,实际用时 "+workTime +" 分钟");

  73:                 }

  74:                 countDownLatch.countDown();

  75:         }

  76:  

  77:         public boolean isForce() {

  78:                 return isForce;

  79:         }

  80:  

  81:         public void setForce(boolean isForce) {

  82:                 this.isForce = isForce;

  83:         }

  84: }

  85:  

  86: class Teacher implements Runnable{

  87:  

  88:         private DelayQueue<Student> students;

  89:  

  90:         public Teacher(DelayQueue<Student> students) {

  91:                 this.students = students;

  92:         }

  93:  

  94:         @Override

  95:         public void run() {

  96:                 try {

  97:                         System.out.println("exam start");

  98:                         while (!Thread.interrupted())

  99:                                 students.take().run();

 100:                 }catch (InterruptedException e){

 101:                         System.out.println("exam end");

 102:                 }

 103:         }

 104: }

 105:  

 106: class EndExam extends Student{

 107:         private DelayQueue<Student> students;

 108:         private CountDownLatch countDownLatch;

 109:         private Thread teacher;

 110:  

 111:         public EndExam(DelayQueue<Student> students,long workTime,CountDownLatch countDownLatch,Thread teacher){

 112:                 super("强制收卷",workTime,countDownLatch);

 113:                 this.students = students;

 114:                 this.countDownLatch = countDownLatch;

 115:                 this.teacher = teacher;

 116:         }

 117:  

 118:         @Override

 119:         public void run() {

 120:                 teacher.interrupt();

 121:                 System.out.println("强制收卷");

 122:                 Student temp;

 123:                 for (Iterator<Student> iterator = students.iterator();iterator.hasNext();){

 124:                         temp = iterator.next();

 125:                         temp.setForce(true);

 126:                         temp.run();

 127:                 }

 128:                 countDownLatch.countDown();

 129:         }

 130: }

四. Semaphore

Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

   1: public class SemaphoreTest {

   2:  

   3:      public static void main(String[] args) {  

   4:         // 线程池 

   5:         ExecutorService exec = Executors.newCachedThreadPool();  

   6:         // 只能5个线程同时访问 

   7:         final Semaphore semp = new Semaphore(5);  

   8:         // 模拟20个客户端访问 

   9:         for (int index = 0; index < 20; index++) {

  10:             final int NO = index;  

  11:             Runnable run = new Runnable() {  

  12:                 public void run() {  

  13:                     try {  

  14:                         // 获取许可 

  15:                         semp.acquire();  

  16:                         System.out.println("Accessing: " + NO);  

  17:                         Thread.sleep((long) (Math.random() * 10000));  

  18:                         // 访问完后,释放 ,如果屏蔽下面的语句,则在控制台只能打印5条记录,之后线程一直阻塞

  19:                         semp.release();  

  20:                     } catch (InterruptedException e) {  

  21:                     }  

  22:                 }  

  23:             };  

  24:             exec.execute(run);  

  25:         }  

  26:         // 退出线程池 

  27:         exec.shutdown();  

  28:     }  

  29: }

java.util.concurrent中的常用组件的更多相关文章

  1. java.util.concurrent中的几种同步工具类

    java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...

  2. java.util.concurrent

    软件包 java.util.concurrent 的描述 在并发编程中很常用的实用工具类.此包包括了几个小的.已标准化的可扩展框架,以及一些提供有用功能的类,没有这些类,这些功能会很难实现或实现起来冗 ...

  3. java.util.concurrent介绍【转】

    java.util.concurrent介绍   java.util.concurrent 包含许多线程安全.测试良好.高性能的并发构建块.不客气地说,创建 java.util.concurrent ...

  4. Java 理论与实践: 流行的原子——新原子类是 java.util.concurrent 的隐藏精华(转载)

    简介: 在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待.无锁定的算法.在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化.请跟随并 ...

  5. 你所不知道的五件事情--java.util.concurrent(第一部分)

                                                                这是Ted Neward在IBM developerWorks中5 things ...

  6. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...

  7. 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁

    上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...

  8. 谈论高并发(二十二)解决java.util.concurrent各种组件(四) 深入了解AQS(二)

    上一页介绍AQS其基本设计思路以及两个内部类Node和ConditionObject实现 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一) 这篇说一 ...

  9. java.util.concurrent各组件分析 一 sun.misc.Unsafe

    java.util.concurrent各组件分析 一 sun.misc.Unsafe 说到concurrent包也叫并发包,该包下主要是线程操作,方便的进行并发编程,提到并发那么锁自然是不可缺少的, ...

随机推荐

  1. 机器学习之K-means算法

    前言            以下内容是个人学习之后的感悟,转载请注明出处~ 简介 在之前发表的线性回归.逻辑回归.神经网络.SVM支持向量机等算法都是监督学习算法,需要样本进行训练,且 样本的类别是知 ...

  2. 你忘记的java的数据类型信息

    java有8种基本数据类型 int long short byte float double char boolean: 三种情况造成数据溢出 无穷大,无穷小, NAN: 常量 声明为final的变量 ...

  3. 关于 jwTextFiled 的使用说明

    我在些项目中多次对一些输入框做了相同的代码操作,终于有一天忍不住了,MD必须写一个小的框架解决这个搬砖的问题.经过一天的战斗,于是 jwTextFied 就默默的诞生了. 地址:https://git ...

  4. 3-2带命令行参数的Java

    命令行参数: 主方法Main 小括号里面的内容就是命令参数: String[] args class ArgsDemo{ public static void main(String[] args){ ...

  5. 5-1 变量与常量 & 6-1课程总结

    变量与常量 常量就是变量定义的的前面加上final final关键字定义常量 新建类FinalDemo 更新常量n的值会报错.常量不可以被修改 常量有个命名规则 一般以大写字母去表示 final in ...

  6. 【WIP】LaTex入门

    创建: 2018/06/15 说明: 这鸟东西实在没什么用的感觉,无奈学校报告要用这个写.无奈抽点时间学一下.                    

  7. PhpStorm插件之Api Debugger

    安装插件 File->Setting->Pluugins   搜索  Api Debugger 如何使用 安装完插件后,RESTART IDE,在编辑器右侧 即可找到最新安装的 Api D ...

  8. Exists 方法

    public void ExistsMethodDemo() { string userId = "123"; string userName = "admin" ...

  9. Legacy C++ MongoDB Driver

    https://docs.mongodb.com/ecosystem/drivers/cpp/

  10. hdoj5875【二分+RMQ】

    全部从我大哥那里学习得来.. 一开始硬着头皮就是根据思路上线段树,明知是T还要写(因为线段树还不是很熟,趁机练一发) 后来果然T了,然后就去学了一发RMQ的ST算法,查询是O(1). ST算法主要: ...