java线程池分析

标签: java 线程池 分析 | 发表时间:2012-02-17 18:51 | 作者:脉凌网络
出处:http://www.blogjava.net/

SyndContentImpl.value=

    在Java 5.0之前启动一个任务是通过调用Thread类的start()方法来实现的,任务的提于交和执行是同时进行的,如果你想对任务的执行进行调度或是控制 同时执行的线程数量就需要额外编写代码来完成。5.0里提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接 池的线程池来执行任务。这个架构主要有三个接口和其相应的具体类组成。这三个接口是Executor, ExecutorService、ScheduledExecutorService,让我们先用一个图来显示它们的关系:

   

 


图的左侧是接口,图的右侧是这些接口的具体类。注意Executor是没有直接具体实现的。

 

Executor 接口:是用来执行Runnable任务的,它只定义一个方法:

 

  • execute( Runnable command):执行Ruannable类型的任务

 

ExecutorService 接口:ExecutorService继承了Executor的方法,并提供了执行Callable任务和中止任务执行的服务,其定义的方法主要有:

 

  • submit( task):可用来提交Callable或Runnable任务,并返回代表此任务的Future对象
  • invokeAll( collection of tasks):批处理任务集合,并返回一个代表这些任务的Future对象集合
  • shutdown():在完成已提交的任务后关闭服务,不再接受新任务
  • shutdownNow():停止所有正在执行的任务并关闭服务。
  • isTerminated():测试是否所有任务都执行完毕了。
  • isShutdown():测试是否该ExecutorService已被关闭

 

ScheduledExecutorService 接口在ExecutorService的基础上,ScheduledExecutorService提供了按时间安排执行任务的功能,它提供的方法主要有:

 

  • schedule( task, initDelay): 安排所提交的Callable或Runnable任务在initDelay指定的时间后执行。
  • scheduleAtFixedRate():安排所提交的Runnable任务按指定的间隔重复执行
  • scheduleWithFixedDelay():安排所提交的Runnable任务在每次执行完后,等待delay所指定的时间后重复执行。

 

 

 

重要的Executors

 

虽然以上提到的接口有其实现的具体类,但为了方便Java 5.0建议使用Executors的工具类来得到Executor接口的具体对象,需要注意的是Executors是一个类,不是Executor的复数 形式。Executors提供了以下一些static的方法:

 

  • callable( Runnable task): 将Runnable的任务转化成Callable的任务
  • newSingleThreadExecutor: 产生一个ExecutorService对象,这个对象只有一个线程可用来执行任务,若任务多于一个,任务将按先后顺序执行。
  • newCachedThreadPool(): 产生一个ExecutorService对象,这个对象带有一个线程池,线程池的大小会根据需要调整,线程执行完任务后返回线程池,供执行下一次任务使用。
  • newFixedThreadPool( int poolSize):产生一个ExecutorService对象,这个对象带有一个大小为poolSize的线程池,若任务数量大于poolSize,任务会被放在一个queue里顺序执行。
  • newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,若任务多于一个,任务将按先后顺序执行。
  • newScheduledThreadPool( int poolSize): 产生一个ScheduledExecutorService对象,这个对象的线程池大小为poolSize,若任务数量大于poolSize,任务会在一个queue里等待执行

 

 

 

举例说明:

 

应用Executors来建立Thread pool

 

 

 

有时候您需要建立一堆Thread来执行一些小任务,然而频繁的建立Thread有时会是个开销,因为Thread的建立必须与作业系统互动,如果能建立一个Thread pool来管理这些小的Thread并加以重复使用,对于系统效能会是个改善的方式。

您可以使用Executors来建立Thread pool,Executors有几个static方法,列出如下:

 

方法 说明
newCachedThreadPool 建立可以快取的Thread,每个Thread预设可idle 60秒

newFixedThreadPool

包括固定数量的Thread

newSingleThreadExecutor

只有一个Thread,循序的执行指定给它的每个任务
newScheduledThreadPool 可排程的Thread
newSingleThreadScheduledExecutor 单一可排程的Thread

 

举个简单的实例,下面的程式使用newFixedThreadPool方法建立Thread pool,当中包括五个可以重复使用的Thread,您可以指定Runnable物件给它,程式中会产生十个Runnable物件,由于Thread pool中只有五个可用的Thread,所以后来建立的五个Runnable必须等待有空闲的Thread才会被执行:

 

  • ExecutorDemo.java

 

package onlyfun.caterpillar;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo {
 public static void main(String[] args) {
  ExecutorService service = Executors.newFixedThreadPool(5);

  for(int i = 0; i < 10; i++) {
   final int count = i;
   service.submit
(new Runnable() {
    public void run() {
     System.out.println(count);
     try {
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }

    }
   });
  }

  service.shutdown(); // 最后记得关闭Thread pool

 }
}

 

submit()方法也接受实作Callable介面的物件,最后传回Future物件,可以取得Callable执行过后的传回结果。

如果想利用Executors进行排程,例如排定某个工作30秒后执行:

 

 ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );          scheduler.schedule(new Runnable( ) {                                 public void run() {                                     // 排程工作                                 }                             },                             30, TimeUnit.SECONDS);

 

或排定某个工作5秒后执行,之后每30秒执行一次:

 

 ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );          final ScheduledFuture future = scheduler.scheduleAtFixedRate(new Runnable( ) {                                 public void run() {                                     // 排程工作                                     System.out.println("t");                                 }                             },                             0, 5, TimeUnit.SECONDS);                   // 排定 60 秒后取消future          scheduler.schedule(new Runnable( ) {              public void run( ) {                future.cancel(false);              }            }, 60, TimeUnit.SECONDS);如上所示,想要取消排程任务,可以呼叫ScheduledFuture的cancel()方法。

 



脉凌网络 2012-02-17 18:51 发表评论

相关 [java 线程池 分析] 推荐:

java线程池分析

- - BlogJava-首页技术区
    在Java 5.0之前启动一个任务是通过调用Thread类的start()方法来实现的,任务的提于交和执行是同时进行的,如果你想对任务的执行进行调度或是控制 同时执行的线程数量就需要额外编写代码来完成. 5.0里提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接 池的线程池来执行任务.

Java线程池

- - 企业架构 - ITeye博客
线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的. 在jdk1.5之后这一情况有了很大的改观. Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用. 为我们在开发中处理线程的问题提供了非常大的帮助.

Java 线程池

- - 编程语言 - ITeye博客
在项目中,系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互. 在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存周期很短的线程时,更应该考虑使用线程池. 使用线程池可以有效地控制系统中并发线程的数量,当系统中包含大量并发线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过此数.

文章: JAVA线程池的分析和使用

- - InfoQ cn
合理利用线程池能够带来三个好处. 通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 当任务到达时,任务可以不需要等到线程创建就能立即执行. 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控. 但是要做到合理的利用线程池,必须对其原理了如指掌.

Java线程池应用

- - CSDN博客架构设计推荐文章
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务. 2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机). Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具.

Java线程池总结

- - Java - 编程语言 - ITeye博客
  假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间. 当T1 + T3 远大于 T2时,采用多线程技术可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     线程池就是一个线程的容器,每次只执行额定数量的线程, 线程池作用就是限制系统中执行线程的数量.

java 线程池原理及几种线程池详解

- - CSDN博客综合推荐文章
服务器经常出现处理大量单个任务处理的时间很短而请求的数目却是巨大的请求. 构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务. 实际上,对于原型开发这种方法工作得很好,但如果试图部署以这种方式运行的服务器应用程序,那么这种方法的严重不足就很明显.

Java四种线程池的使用

- - ITeye博客
Java通过Executors提供四种线程池,分别为:. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行.

java 线程池使用 Runnable&Callable&Future

- - Java - 编程语言 - ITeye博客
执行一次线程,调用Runnable接口实现.  当线程池执行Runnable后,返回的Future.get()总是null. DefaultRunnable代码如下:. 执行一次线程,调用Callable接口实现.  当线程池执行Callable时,返回的Future.get() 会返回Callable的返回值.

Java 线程池的原理与实现

- - CSDN博客编程语言推荐文章
这几天主要是狂看源程序,在弥补了一些以前知识空白的同时,也学会了不少新的知识(比如 NIO),或者称为新技术吧. 线程池就是其中之一,一提到线程,我们会想到以前《操作系统》的生产者与消费者,信号量,同步控制等等. 一提到池,我们会想到数据库连接池,但是线程池又如何呢. 建议:在阅读本文前,先理一理同步的知识,特别是syncronized同步关键字的用法.