`

实战Concurrent(1)

阅读更多

来自http://www.iteye.com/topic/363625

 

编写多线程的程序一直都是一件比较麻烦的事情,要考虑很多事情,处理不好还会出很多意想不到的麻烦。加上现在很多开发者接触到的项目都是打着企业级旗号的B/S项目,大多数人都很少涉及多线程,这又为本文的主角增加了一份神秘感。

 

讲到Java多线程,大多数人脑海中跳出来的是Thread、Runnable、synchronized……这些是最基本的东西,虽然已经足够强大,但想要用好还真不容易。从JDK 1.5开始,增加了java.util.concurrent包,它的引入大大简化了多线程程序的开发(要感谢一下大牛Doug Lee)。

 

java.util.concurrent包分成了三个部分,分别是java.util.concurrent、java.util.concurrent.atomic和java.util.concurrent.lock。内容涵盖了并发集合类、线程池机制、同步互斥机制、线程安全的变量更新工具类、锁等等常用工具。

 

为了便于理解,本文使用一个例子来做说明,交代一下它的场景:

假设要对一套10个节点组成的环境进行检查,这个环境有两个入口点,通过节点间的依赖关系可以遍历到整个环境。依赖关系可以构成一张有向图,可能存在环。为了提高检查的效率,考虑使用多线程。

 

1、Executors

通过这个类能够获得多种线程池的实例,例如可以调用newSingleThreadExecutor()获得单线程的ExecutorService,调用newFixedThreadPool()获得固定大小线程池的ExecutorService。拿到ExecutorService可以做的事情就比较多了,最简单的是用它来执行Runnable对象,也可以执行一些实现了Callable<T>的对象。用Thread的start()方法没有返回值,如果该线程执行的方法有返回值那用ExecutorService就再好不过了,可以选择submit()、invokeAll()或者invokeAny(),根据具体情况选择合适的方法即可。

Java代码 
  1. package  service;  
  2.   
  3. import  java.util.ArrayList;  
  4. import  java.util.List;  
  5. import  java.util.concurrent.ExecutionException;  
  6. import  java.util.concurrent.ExecutorService;  
  7. import  java.util.concurrent.Executors;  
  8. import  java.util.concurrent.Future;  
  9. import  java.util.concurrent.TimeUnit;  
  10.   
  11. /**  
  12.  * 线程池服务类  
  13.  *   
  14.  * @author DigitalSonic  
  15.  */   
  16. public   class  ThreadPoolService {  
  17.     /**  
  18.      * 默认线程池大小  
  19.      */   
  20.     public   static   final   int   DEFAULT_POOL_SIZE    =  5 ;  
  21.   
  22.     /**  
  23.      * 默认一个任务的超时时间,单位为毫秒  
  24.      */   
  25.     public   static   final   long  DEFAULT_TASK_TIMEOUT =  1000 ;  
  26.   
  27.     private   int               poolSize             = DEFAULT_POOL_SIZE;  
  28.     private  ExecutorService  executorService;  
  29.   
  30.     /**  
  31.      * 根据给定大小创建线程池  
  32.      */   
  33.     public  ThreadPoolService( int  poolSize) {  
  34.         setPoolSize(poolSize);  
  35.     }  
  36.   
  37.     /**  
  38.      * 使用线程池中的线程来执行任务  
  39.      */   
  40.     public   void  execute(Runnable task) {  
  41.         executorService.execute(task);  
  42.     }  
  43.   
  44.     /**  
  45.      * 在线程池中执行所有给定的任务并取回运行结果,使用默认超时时间  
  46.      *   
  47.      * @see #invokeAll(List, long)  
  48.      */   
  49.     public  List<Node> invokeAll(List<ValidationTask> tasks) {  
  50.         return  invokeAll(tasks, DEFAULT_TASK_TIMEOUT * tasks.size());  
  51.     }  
  52.   
  53.     /**  
  54.      * 在线程池中执行所有给定的任务并取回运行结果  
  55.      *   
  56.      * @param timeout 以毫秒为单位的超时时间,小于0表示不设定超时  
  57.      * @see java.util.concurrent.ExecutorService#invokeAll(java.util.Collection)  
  58.      */   
  59.     public  List<Node> invokeAll(List<ValidationTask> tasks,  long  timeout) {  
  60.         List<Node> nodes = new  ArrayList<Node>(tasks.size());  
  61.         try  {  
  62.             List<Future<Node>> futures = null ;  
  63.             if  (timeout <  0 ) {  
  64.                 futures = executorService.invokeAll(tasks);  
  65.             } else  {  
  66.                 futures = executorService.invokeAll(tasks, timeout, TimeUnit.MILLISECONDS);  
  67.             }  
  68.             for  (Future<Node> future : futures) {  
  69.                 try  {  
  70.                     nodes.add(future.get());  
  71.                 } catch  (ExecutionException e) {  
  72.                     e.printStackTrace();  
  73.                 }  
  74.             }  
  75.         } catch  (InterruptedException e) {  
  76.             e.printStackTrace();  
  77.         }  
  78.         return  nodes;  
  79.     }  
  80.   
  81.     /**  
  82.      * 关闭当前ExecutorService  
  83.      *   
  84.      * @param timeout 以毫秒为单位的超时时间  
  85.      */   
  86.     public   void  destoryExecutorService( long  timeout) {  
  87.         if  (executorService !=  null  && !executorService.isShutdown()) {  
  88.             try  {  
  89.                 executorService.awaitTermination(timeout, TimeUnit.MILLISECONDS);  
  90.             } catch  (InterruptedException e) {  
  91.                 e.printStackTrace();  
  92.             }  
  93.             executorService.shutdown();  
  94.         }  
  95.     }  
  96.   
  97.     /**  
  98.      * 关闭当前ExecutorService,随后根据poolSize创建新的ExecutorService  
  99.      */   
  100.     public   void  createExecutorService() {  
  101.         destoryExecutorService(1000 );  
  102.         executorService = Executors.newFixedThreadPool(poolSize);  
  103.     }  
  104.   
  105.     /**  
  106.      * 调整线程池大小  
  107.      * @see #createExecutorService()  
  108.      */   
  109.     public   void  setPoolSize( int  poolSize) {  
  110.         this .poolSize = poolSize;  
  111.         createExecutorService();  
  112.     }  
  113. }  
 

这里要额外说明一下invokeAll()和invokeAny()方法。前者会执行给定的所有Callable<T>对象,等所有任务完成后返回一个包含了执行结果的List<Future<T>>,每个Future.isDone()都是true,可以用Future.get()拿到结果;后者只要完成了列表中的任意一个任务就立刻返回,返回值就是执行结果。

还有一个比较诡异的地方
本代码是在JDK 1.6下编译测试的,如果在JDK 1.5下测试,很可能在invokeAll和invokeAny的地方出错。明明ValidationTask实现了 Callable<Node>,可是它死活不认,类型不匹配,这时可以将参数声明由List<ValidationTask>改为 List<Callable<Node>>。
造成这个问题的主要原因是两个版本中invokeAll和invokeAny的方法签名不同,1.6里是invokeAll(Collection<? extends Callable<T>> tasks),而1.5里是invokeAll(Collection<Callable<T>> tasks)。网上也有人遇到类似的问题(invokeAll() is not willing to acept a Collection<Callable<T>> )。

 

和其他资源一样,线程池在使用完毕后也需要释放,用shutdown()方法可以关闭线程池,如果当时池里还有没有被执行的任务,它会等待任务执行完毕,在等待期间试图进入线程池的任务将被拒绝。也可以用shutdownNow()来关闭线程池,它会立刻关闭线程池,没有执行的任务作为返回值返回。

分享到:
评论

相关推荐

    实战Concurrent

    "实战Concurrent"这一主题主要聚焦于Java中的并发编程,它涉及到多线程、并发容器、同步机制以及性能优化等多个方面。通过深入理解并实践这些概念,开发者可以更好地设计和实现能够充分利用现代多核处理器能力的应用...

    实战Concurrent-BlockQueue

    《实战Concurrent-BlockQueue》 在Java并发编程领域,`Concurrent-BlockQueue`是一个重要的数据结构,它结合了线程安全与高效性能。本文将深入探讨`ConcurrentLinkedQueue`、`ArrayBlockingQueue`以及`...

    Doug Lea, Concurrent Programming in Java Design Principles and Patterns

    1. **并发基础**:首先,书中介绍了并发编程的基本概念,包括线程、进程、同步与互斥等。同时,它讲解了Java中的线程创建、管理和协作机制,如Thread类和Runnable接口的使用。 2. **线程安全**:讨论了线程安全问题...

    使用Java并发编程Concurrent Programming Using Java

    Java平台提供了丰富的API支持并发编程,如`java.util.concurrent`包下的各种类和接口,这些工具可以帮助开发者更高效地管理多线程环境下的任务调度和数据共享问题。 ### Java并发编程基础 #### 1. 多线程基础 - **...

    java并发编程实战源码-concurrent-programming:《Java并发编程实战》源码整理

    《Java并发编程实战》这本书是Java并发编程领域的一本经典之作,它深入浅出地讲解了如何在Java环境中高效、安全地进行多线程编程。源码整理集合`concurrent-programming-master`提供了书中示例代码,对于学习和理解...

    concurrent-programming:《实战java高并发程序设计》源码整理

    《实战java高并发程序设计》源码整理联系作者十三的java的学习交流QQ群: 881582471 , 658365129(已满)相关文章书籍封面目录第1章走入并行世界1.1何去何从的并行计算1.1.1忘掉那该死的并行1.1.2可怕的现实:摩尔...

    Java 并发编程实战.pdf

    此外,该书可能会对Java中一些新的并发API进行探讨,如java.util.concurrent包下的工具类和接口,例如Executor框架、Future、CompletableFuture、ConcurrentHashMap、Semaphore等。这些工具类和接口在构建大规模并发...

    (PDF带目录)《Java 并发编程实战》,java并发实战,并发

    1. **线程与进程**:书中首先会介绍操作系统中的线程和进程概念,以及它们在Java中的实现。Java通过`Thread`类支持线程的创建和管理,而`Runnable`接口提供了另一种实现多线程的方式。 2. **同步机制**:Java中的...

    《java 并发编程实战高清PDF版》

    《Java并发编程实战》是一本深入探讨Java平台并发编程的权威指南。这本书旨在帮助开发者理解和掌握在Java环境中创建高效、可扩展且可靠的多线程应用程序的关键技术和实践。它涵盖了从基本概念到高级主题的广泛内容,...

    Java并发编程:设计原则与模式(Concurrent.Programming.in.Java)(中英版)

    这本书不仅提供了丰富的理论知识,还介绍了实战中的设计原则和模式,对于Java开发者来说是不可或缺的参考资源。 在Java并发编程领域,理解设计原则至关重要,因为它们指导我们编写高效、安全且可维护的多线程代码。...

    java concurrent in practive

    《Java并发编程实战》还会讨论`java.util.concurrent`包中的高级并发工具,如`ExecutorService`和`Future`,它们可以方便地管理和控制线程池,提高系统的并行处理能力。`CountDownLatch`、`CyclicBarrier`和`...

    Concurrent Programming on Windows

    五、实战技巧与理论知识的完美结合 Steve Teixeira,微软Parallel Computing Platform部门的产品单元经理,对本书给予了高度评价。他认为本书既全面覆盖了Windows平台上的并发编程,又实用地介绍了可以直接应用于...

    python爬虫项目实战

    1. **需求分析**:明确你要爬取的数据类型、来源以及目的,这将决定你选择的爬虫策略和技术。 2. **URL管理和网络请求**:使用`requests`库发送GET或POST请求,获取网页HTML内容。同时,要处理URL管理,防止重复...

    实战Java高并发程序设计(高清版)

    4. **并发工具类**:Java并发包(java.util.concurrent)中包含了很多实用的工具类,如`Future`、`CompletableFuture`、`Semaphore`等,这些工具可以帮助开发者更好地管理并发任务。 5. **J.U.C框架**:Java并发 ...

    Java并发编程实战

    第1章 简介 1.1 并发简史 1.2 线程的优势 1.2.1 发挥多处理器的强大能力 1.2.2 建模的简单性 1.2.3 异步事件的简化处理 1.2.4 响应更灵敏的用户界面 1.3 线程带来的风险 1.3.1 安全性问题 1.3.2 活跃性...

    java并发编程实战高清版pdf

    1. **线程基础**:线程是程序执行的最小单位,Java中的`Thread`类提供了创建和管理线程的方法。了解线程的生命周期(新建、就绪、运行、阻塞、死亡)和状态转换是非常基础的。 2. **同步机制**:Java提供了多种同步...

    jvm开发实战项目案例分析

    在《大神带你学Java(第1天)》的文件中,可能会详细讲解如何使用各种工具如JConsole、VisualVM或JProfiler来监控和诊断JVM状态,包括CPU使用率、内存分配、线程状态等。通过这些工具,我们可以定位性能瓶颈,比如...

    jvm调优实战经验

    1. **多功能养鱼塘-JVM内存** JVM内存分为两个主要部分:堆内存(Heap)和非堆内存(Non-Heap)。堆内存是JVM用来存储类实例和数组的主要区域,可以根据需求动态扩展或收缩。堆内存进一步细分为年轻代(Young ...

Global site tag (gtag.js) - Google Analytics