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

[笔记][Java7并发编程实战手册]系列目录


简介

newCachedThreadPool()创建的线程池的特性是:
  自动回收不使用的线程(终止并从缓存中移除那些已有 60 秒钟未被使用的线程),(在无可用线程的情况下)自动的为新来的task创建新线程。
使用场景:
  在小任务量,任务时间执行短的场景下能提高性能。

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

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

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

为了便于跨大量上下文使用,此类提供了很多可调整的参数和扩展钩子 (hook)。但是,强烈建议程序员使用较为方便的 Executors 工厂方法构建服务:
1. Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)
2. Executors.newFixedThreadPool(int)(固定大小线程池)
3. Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。


本章使用心得newCachedThreadPool()

  1. 使用Executors来构建预置服务。
  2. 要记得使用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打印出来的线程池中的一些任务信息。 没什么可说,先上手。再深入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值