Concurrent多线程控制

在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 otherTest.thread;
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("in="+count);
     try {
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     System.out.println("out="+count); 
    }
   });
  }
  
  service.shutdown(); // 最后记得关闭Thread pool
 }
}
-----
 执行结果,显示最多只有5个线程在正在运行中,其他多余的线程处于等待状态。
in=0
in=2
in=1
in=3
in=4
out=0
in=5
out=2
in=6
out=1
out=3
out=4
in=8
in=7
in=9
out=6
out=5
out=8
out=7
out=9


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

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

Java代码 复制代码 收藏代码
  1. ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );
  2. scheduler.schedule(new Runnable( ) {
  3. public void run() {
  4. // 排程工作
  5. }
  6. },
  7. 30, TimeUnit.SECONDS);
 

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

 
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );  
  1. final ScheduledFuture future = scheduler.scheduleAtFixedRate(new Runnable( ) {  
  2. public void run() {  
  3. // 排程工作  
  4. System.out.println("t");  
  5. }  
  6. },  
  7. 30, 5, TimeUnit.SECONDS);  
  8. // 排定 60 秒后取消future  
  9. scheduler.schedule(new Runnable( ) {  
  10. public void run( ) {  
  11. future.cancel(false);  
  12. }  
  13. }, 60, TimeUnit.SECONDS);  

如上所示,想要取消排程任务,可以呼叫ScheduledFuture的cancel()方法。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
j-concurrent 00 IBM developerWorks 中国 : Java 多线程与并发编程专题 02 Java 程序中的多线程 03 编写多线程的 Java 应用程序 04 如果我是国王:关于解决 Java编程语言线程问题的建议 (2) 05 构建Java并发模型框架 (2) 06 Java 技术: 使您轻松地进行多线程应用程序编程 07 使用JAVA建立稳定的多线程服务器 (3) 08 线程池的介绍及简单实现 09 Java实时多任务调度过程中的安全监控设计 (3) 10 不要重新分配被锁定对象的对象引用 11 以全局的固定顺序获取多个锁来避免死锁 12 Java单例对象同步问题探讨 13 Java 理论与实践: 描绘线程安全性 (2) 14 编写高效的线程安全类 (2) 15 轻松使用线程 同步不是敌人.mht 16 轻松使用线程 减少争用.mht 17 轻松使用线程 不共享有时是最好的.mht 18 适用于 Java 程序员的 CSP,第 1 部分.mht 19 适用于 Java 程序员的 CSP ,第 2 部分.mht 20 适用于 Java 程序员的 CSP ,第 3 部分.mht 21 实现一个不受约束的不变性模型.mht 22 实时 Java,第 3 部分 线程化和同步.mht 23 IBM 的 Java 诊断,第 3 部分 使用面向 Java 的 Lock Analyzer 诊断同步和锁问题.mht 24 实现 Java 多线程并发控制框架.mht 25 多线程、多平台环境中的跟踪.mht 26 使用 ConTest 进行多线程单元测试.mht 27 实现非阻塞套接字的一种简单方法.mht 28 基于事件的NIO多线程服务器.mht 29 驯服 Tiger 并发集合.mht 30 Java5 多线程实践.mht 31 Java 理论与实践 并发集合类.mht 32 Java 理论与实践 构建一个更好的 HashMap.mht 33 Java 理论与实践 JDK 5_0 中更灵活、更具可伸缩性的锁定机制.mht 34 Java 理论与实践 流行的原子.mht 35 Java 理论与实践 非阻塞算法简介.mht 36 Java 理论与实践 处理 InterruptedException.mht 37 Java 理论与实践 正确使用 Volatile 变量.mht 38 使用泛型和并发改善集合.mht
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值