您的位置:首页 > 编程语言 > Java开发

[笔记][Java7并发编程实战手册]4.2 创建线程执行器newCachedThreadPool无界线程池

2015-08-24 22:27 489 查看
[笔记][Java7并发编程实战手册]系列目录

简介

newCachedThreadPool()创建的线程池的特性是:

  自动回收不使用的线程(终止并从缓存中移除那些已有 60 秒钟未被使用的线程),(在无可用线程的情况下)自动的为新来的task创建新线程。

使用场景:

  在小任务量,任务时间执行短的场景下能提高性能。

在jdk api中的介绍如下一部分,其他的请查看api文档

  ThreadPoolExecutor是一个一个 ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置。

  线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。

为了便于跨大量上下文使用,此类提供了很多可调整的参数和扩展钩子 (hook)。但是,强烈建议程序员使用较为方便的 Executors 工厂方法构建服务:

1. Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)

2. Executors.newFixedThreadPool(int)(固定大小线程池)

3. Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。

本章使用心得newCachedThreadPool()

使用Executors来构建预置服务。

要记得使用shutdown() 来关闭执行器,如果不关闭,则一直等待新任务的到来,该方法在api中的解释:按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。如果已经关闭,则调用没有其他作用。

上手使用伪代码:

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); //创建线程池执执行器服务
executor.execute(task); //把Runnable交给执行器执行
executor.shutdown(); //申请关闭执行器


简单的示例示例

场景描述:以下示例就是演示了,把一组线程交给执行器执行,在执行器中打印执行器中线程池中的一些任务信息。

/**
* Created by zhuqiang on 2015/8/24 0024.
*/
public class Client {
public static void main(String[] args) throws InterruptedException {
Service s = new Service();
for (int i = 0; i <  3; i++) {
Task task = new Task(new Date(), "task" + i);
TimeUnit.SECONDS.sleep(3); // 休眠3秒,以便等待有任务执行完的线程。在信息里面能看到更丰富的 执行器的管理信息
s.executorTask(task);
}
s.endService();  // 1  如果注释此代码,本程序将挂起。不会结束
}
}
/** 模拟任务类*/
class  Task implements  Runnable{
private Date initDate; //初始化时间
private String name;  //任务名称

public Task(Date initDate, String name) {
this.initDate = initDate;
this.name = name;
}

@Override
public void run() {
Thread t = Thread.currentThread();
System.out.printf("  start-------------%s,任务名称:%s,时间:%s\n", t.getName(),this.name,initDate);
try {
long  time = (long)(Math.random() * 10); //模拟工作时间
TimeUnit.SECONDS.sleep(time);
System.out.printf("  end-------------%s,任务名称:%s,耗时:%s\n", t.getName(),this.name,time);
}catch (Exception e){
e.printStackTrace();
}
}
}
/** 服务类,接收每一个任务*/
class Service{
private ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();

/** 接受任务,直接丢给了 线程池执行*/
public void executorTask(Task task){
System.out.println("service:接收了一个task");
executor.execute(task);
System.out.printf("service:pool执行器中线程中实际的线程数量:%d,执行器中正在执行任务的线程数量:%d,执行器中已经完成的任务数量:%d\n",executor.getPoolSize(),executor.getActiveCount(),executor.getCompletedTaskCount());
}
/** */
public void endService(){
System.out.printf("service-----------------shutdown--------------:pool执行器中线程中实际的线程数量:%d,执行器中正在执行任务的线程数量:%d,执行器中已经完成的任务数量:%d\n",executor.getPoolSize(),executor.getActiveCount(),executor.getCompletedTaskCount());
executor.shutdown();
}
}


某一次的运行结果:

service:接收了一个task
start-------------pool-1-thread-1,任务名称:task0,时间:Mon Aug 24 22:33:23 CST 2015
service:pool执行器中线程中实际的线程数量:1,执行器中正在执行任务的线程数量:1,执行器中已经完成的任务数量:0
service:接收了一个task
service:pool执行器中线程中实际的线程数量:2,执行器中正在执行任务的线程数量:2,执行器中已经完成的任务数量:0
start-------------pool-1-thread-2,任务名称:task1,时间:Mon Aug 24 22:33:26 CST 2015
end-------------pool-1-thread-1,任务名称:task0,耗时:4
service:接收了一个task
service:pool执行器中线程中实际的线程数量:2,执行器中正在执行任务的线程数量:1,执行器中已经完成的任务数量:1
start-------------pool-1-thread-1,任务名称:task2,时间:Mon Aug 24 22:33:29 CST 2015
service-----------------shutdown--------------:pool执行器中线程中实际的线程数量:2,执行器中正在执行任务的线程数量:2,执行器中已经完成的任务数量:1
end-------------pool-1-thread-2,任务名称:task1,耗时:4
end-------------pool-1-thread-1,任务名称:task2,耗时:9


结果说明

仔细看上面的线程名称,和task名称,可以看出来,3个任务只使用了2个线程。如果在更多的任务中,线程得到了复用。性能更好了

可以看到上面打印的信息。一些api打印出来的线程池中的一些任务信息。 没什么可说,先上手。再深入
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: