`

java.util.concurrent详解(一) Latch/Barrier

    博客分类:
  • lock
阅读更多

Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可以帮助开发者编写高效、易维护、结构清晰的Java多线程程序。从这篇blog起,我将跟大家一起共同学习这些新的Java多线程构件

1. CountDownLatch
    我们先来学习一下JDK1.5 API中关于这个类的详细介绍:
“一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。”

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

    下面我举一个非常简单的例子。假设我们要打印1-100,最后再输出“Ok“。1-100的打印顺序不要求统一,只需保证“Ok“是在最后出现即可。

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

具体代码如下(本代码参考了JDK示例代码):

Java代码 复制代码  收藏代码
  1. import  java.util.concurrent.CountDownLatch;   
  2. /**  
  3.  * 示例:CountDownLatch的使用举例  
  4.  * Mail: ken@iamcoding.com  
  5.  * @author janeky  
  6.  */   
  7. public   class  TestCountDownLatch {   
  8.      private   static   final   int  N =  10 ;   
  9.   
  10.      public   static   void  main(String[] args)  throws  InterruptedException {   
  11.         CountDownLatch doneSignal =  new  CountDownLatch(N);   
  12.         CountDownLatch startSignal =  new  CountDownLatch( 1 ); //开始执行信号   
  13.   
  14.          for  ( int  i =  1 ; i <= N; i++) {   
  15.              new  Thread( new  Worker(i, doneSignal, startSignal)).start(); //线程启动了   
  16.         }   
  17.         System.out.println( "begin------------" );   
  18.         startSignal.countDown(); //开始执行啦   
  19.         doneSignal.await(); //等待所有的线程执行完毕   
  20.         System.out.println( "Ok" );   
  21.   
  22.     }   
  23.   
  24.      static   class  Worker  implements  Runnable {   
  25.          private   final  CountDownLatch doneSignal;   
  26.          private   final  CountDownLatch startSignal;   
  27.          private   int  beginIndex;   
  28.   
  29.         Worker( int  beginIndex, CountDownLatch doneSignal,   
  30.                 CountDownLatch startSignal) {   
  31.              this .startSignal = startSignal;   
  32.              this .beginIndex = beginIndex;   
  33.              this .doneSignal = doneSignal;   
  34.         }   
  35.   
  36.          public   void  run() {   
  37.              try  {   
  38.                 startSignal.await();  //等待开始执行信号的发布   
  39.                 beginIndex = (beginIndex -  1 ) *  10  +  1 ;   
  40.                  for  ( int  i = beginIndex; i <= beginIndex +  10 ; i++) {   
  41.                     System.out.println(i);   
  42.                 }   
  43.             }  catch  (InterruptedException e) {   
  44.                 e.printStackTrace();   
  45.             }  finally  {   
  46.                 doneSignal.countDown();   
  47.             }   
  48.         }   
  49.     }   
  50. }  
[java] view plain copy
  1.   



    总结:CounDownLatch对于管理一组相关线程非常有用。上述示例代码中就形象地描述了两种使用情况。第一种是计算器为1,代表了两种状态,开 关。第二种是计数器为N,代表等待N个操作完成。今后我们在编写多线程程序时,可以使用这个构件来管理一组独立线程的执行。

2. CyclicBarrier
    我们先来学习一下JDK1.5 API中关于这个类的详细介绍:
    “一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
    CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

    我们在学习CountDownLatch的时候就提到了CyclicBarrier。两者究竟有什么联系呢?引用[JCIP]中的描述“The key difference is that with a barrier, all the threads must come together at a barrier point at the same time in order to proceed. Latches are for waiting for events; barriers are for waiting for other threads。CyclicBarrier等待所有的线程一起完成后再执行某个动作。这个功能CountDownLatch也同样可以实现。但是 CountDownLatch更多时候是在等待某个事件的发生。在CyclicBarrier中,所有的线程调用await方法,等待其他线程都执行完。

    举一个很简单的例子,今天晚上我们哥们4个去Happy。就互相通知了一下:晚上八点准时到xx酒吧门前集合,不见不散!。有个哥们住的近,早早就到了。有的事务繁忙,刚好踩点到了。无论怎样,先来的都不能独自行动,只能等待所有人

代码如下(参考了网上给的一些教程)

Java代码 复制代码  收藏代码
  1. import  java.util.Random;   
  2. import  java.util.concurrent.BrokenBarrierException;   
  3. import  java.util.concurrent.CyclicBarrier;   
  4. import  java.util.concurrent.ExecutorService;   
  5. import  java.util.concurrent.Executors;   
  6.   
  7. public   class  TestCyclicBarrier {   
  8.   
  9.      public   static   void  main(String[] args) {   
  10.        
  11.         ExecutorService exec = Executors.newCachedThreadPool();        
  12.          final  Random random= new  Random();   
  13.            
  14.          final  CyclicBarrier barrier= new  CyclicBarrier( 4 , new  Runnable(){   
  15.              @Override   
  16.              public   void  run() {   
  17.                 System.out.println( "大家都到齐了,开始happy去" );   
  18.             }});   
  19.            
  20.          for ( int  i= 0 ;i< 4 ;i++){   
  21.             exec.execute( new  Runnable(){   
  22.                  @Override   
  23.                  public   void  run() {   
  24.                      try  {   
  25.                         Thread.sleep(random.nextInt( 1000 ));   
  26.                     }  catch  (InterruptedException e) {   
  27.                         e.printStackTrace();   
  28.                     }   
  29.                     System.out.println(Thread.currentThread().getName()+ "到了,其他哥们呢" );   
  30.                      try  {   
  31.                         barrier.await(); //等待其他哥们   
  32.                     }  catch  (InterruptedException e) {   
  33.                         e.printStackTrace();   
  34.                     }  catch  (BrokenBarrierException e) {   
  35.                         e.printStackTrace();   
  36.                     }   
  37.                 }});   
  38.         }   
  39.         exec.shutdown();   
  40.     }   
  41.   
  42. }  



    关于await方法要特别注意一下,它有可能在阻塞的过程中由于某些原因被中断

    总结:CyclicBarrier就是一个栅栏,等待所有线程到达后再执行相关的操作。barrier 在释放等待线程后可以重用。

分享到:
评论

相关推荐

    java并发工具包 java.util.concurrent中文版用户指南pdf

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    java多线程学习-java.util.concurrent详解(一) Latch/Barrier

    `java.util.concurrent`包是Java提供的一个强大的多线程工具库,其中包含了许多类和接口,如`CountDownLatch`和`CyclicBarrier`,它们为程序员提供了更高级别的同步和协调机制。这篇文档将详细解析这两个工具类的...

    Tomcat内存溢出的解决方法(java.util.concurrent.ExecutionException)

    "java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError" 是一个典型的错误提示,它表明在并发执行过程中遇到了内存不足的问题。下面我们将深入探讨这个问题的原因、影响以及如何解决。 内存溢出...

    java.util.logging.Logger使用详解

    ### Java.util.logging.Logger 使用详解 #### 一、创建Logger对象 在Java中,`java.util.logging.Logger` 是标准的日志框架之一,它提供了基础的日志记录功能。为了使用这一功能,首先需要获得 `java.util.logging...

    java并发工具包 java.util.concurrent中文版pdf

    ### Java并发工具包 `java.util.concurrent` 知识点详解 #### 一、引言 随着多核处理器的普及和应用程序复杂度的增加,多线程编程成为了现代软件开发不可或缺的一部分。为了简化并发编程的复杂性,Java 5 引入了 `...

    java.util.concurrent 学习ppt

    Java.util.concurrent是Java 5.0引入的一个重要包,它为多线程编程提供了一组高级并发工具。这个包的设计者是Doug Lea,它的出现是JSR-166的一部分,也被称作Tiger更新。Java.util.concurrent的引入是为了解决传统...

    java.util.concurrent

    java.util.concurrent总体概览图。 收取资源分3分。需要的同学可以下载一下。 java.util.concurrent主要包括5个部分executor,colletions,locks,atomic,tools。 该图详细的列举了并发包下面的结构,包含所有接口和...

    JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用

    JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用是Java多线程编程中的一种重要概念。随着多线程编程的普及,线程池的使用变得越来越频繁。Java中的线程池是通过ThreadPoolExecutor类实现的。 一、...

    The java.util.concurrent Synchronizer Framework

    ### Java.util.concurrent.Synchronizer框架详解 #### 一、引言与背景 随着Java技术的发展,多线程编程成为了一项重要的技术需求。为了更好地支持并发编程,Java平台在J2SE 1.5版本中引入了`java.util.concurrent`...

    java.util.Date与java.sql.Date相互转换

    从继承关系上来看,`java.sql.Date` 是从 `java.util.Date` 继承而来,这意味着 `java.sql.Date` 实际上就是 `java.util.Date` 的一个子类。这种设计使得 `java.sql.Date` 自然地拥有 `java.util.Date` 的所有特性,...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf

    java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    java.util.ConcurrentModificationException 异常问题详解1

    Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...

    用java.util.zip包现数据压缩与解压

    本文将通过一系列的示例来详细介绍如何利用 Java 中的 `java.util.zip` 包进行数据的压缩与解压操作。此外,还将探讨这一技术在网络传输中的应用。 #### 数据压缩算法简介 在深入讨论具体实现之前,我们先简要了解...

    java.util.Date与java.sql.Date互转及字符串转换为日期时间格式.docx

    #### 一、Java.util.Date与Java.sql.Date的基本概念 在Java编程语言中,处理日期和时间时经常使用到`java.util.Date`和`java.sql.Date`这两个类。它们虽然名字相似,但在实际应用中有很大的区别。 - **`java.util....

    Java高性能线程库(java.util.concurrent包的补充)

    一个高性能的Java线程库,该库是 JDK 1.5 中的 java.util.concurrent 包的补充,可用于基于并发消息机制的应用。该类库不提供远程的消息功能,其设计的宗旨是实现一个内存中的消息传递机制. 主要特点有: * All ...

    Exception in thread “main“ java.util.InputMismatchException.pdf

    在Java编程语言中,`java.util.InputMismatchException`是一个常见的运行时异常,它通常发生在尝试从数据源(如控制台、文件或数据库)读取数据时,遇到的数据类型与预期的不匹配。在这个特定的场景中,问题出在主线...

    java.util.concurrent-多线程框架.docx

    多线程编程是 Java 语言中的一大特点,java.util.concurrent 多线程框架则是该特点的体现。该框架提供了多种机制,包括线程池、并发集合、同步器、lock 等,以便开发者更方便地编写高效、可靠的多线程程序。 在 ...

    java.util.concurrent.uml.pdf

    标题中提到了“java.util.concurrent.uml.pdf”,这表明文件是一份Java并发编程工具包java.util.concurrent的UML(统一建模语言)类结构图的PDF格式文件。UML图能够帮助开发者理解Java并发包中的类、接口及其关系,...

Global site tag (gtag.js) - Google Analytics