线程池 (thread pool) 的类型与实现方式

  在许多应用中需要频繁的创建许多生命周期很短的线程,如果用传统方法的话就会造成大量的资源了浪费,java的设计者们考虑到了这点在java中加入了线程池这个特性,它负责管理大量的线程的创建销毁等操作。

  首先我们需要了解一个类:java.util.concurrent.Executors执行器

  执行器类拥有大量的静态工厂方法用于创建线程池

  

方法 描述
newCachedThreadPool 必要时创建线程,处于空闲状态的线程将被保留60秒
newFixedThreadPool 拥有固定数量的线程,并且不会自动销毁空闲状态的线程
newSingleThreadExecutor 该线程池仅有一个线程,会顺序执行任务队列
newScheduledThreadPool 用于预约执行任务的固定线程池
newSingleThreadScheduledExecutor  用于预约执行任务的单线程池

 

 下面我们来详细了解下这些线程池。

 

  newCachedThreadPool:通过名称,不难看出这个方法创建出的线程池,具有数量可变,并且在需要的时候会自动创建更多的线程,并且会自动销毁线程。

  newFixedThreadPool:此线程池与newCachedThreadPool构建出的线程池的主要区别是,线程池在数量上固定,如果任务数量达到上限的话,就会将多余任务加入任务队列,等线程池空出线程时即可执行,这种线程池并不会销毁空闲线程。  

  newSingleThreadExecutor:此方法创建出的线程池相较于其他两个线程较为特殊,此方法创建出的线程数量仅仅为1,也就是说所有除了正在执行的任务外,其余任务均在任务队列中,当线程中的任务执行完毕后,任务队列的第一个任务进入线程开始执行。

  newScheduledThreadPool与 newSingleThreadScheduledExecutor:这两个方法创建出的线程池是用于预定执行的线程池,他们可以用于在初始化后延迟执行,或周期性的执行,两种线程池大体相同,唯一的区别就是可同时执行的线程数量。

 

  当你挑选完的线程池后就需要创建以及使用线程池:

    大概步骤为以下3步:

    1)调用执行器类(Executors)的静态方法来创建线程池

    (2)调用线程池的submit方法提交Runnable或Callable对象

    (3)当不需要添加更多的任务时,调用shutdown关闭入口

  下面通过代码来逐步操作:

    

 1 //创建线程池对象
 2         ExecutorService service = Executors.newCachedThreadPool();
 3         //创建一个用于递增输出i值的runnable对象
 4         Runnable runnable = new Runnable() {
 5             @Override
 6             public void run() {
 7                 for (int i = 0; i < 400; i++) {
 8                     System.out.println(i);
 9                 }
10             }
11         };
12         //调用线程池的submit方法传入runnable(传入的runnable将会自动执行)
13         service.submit(runnable);
14         service.submit(runnable);
15         //当不需要传入更多的任务时调用shutdown方法来关闭入口
16         service.shutdown();

 

 

    需要注意的是如果希望直接停止线程池的一切任务是无法通过shutdown来操作的,因为shutdown仅仅是关闭了入口,但是已经加入的任务还是会继续执行的,这时我们可以调用线程池的shutdownNow方法来操作,shutdownNow的作用是用来关闭线程池的入口并且会尝试终止所有当前线程池内的任务。

//用来关闭线程池入口以及终止所有正在执行的任务
  service.shutdownNow();

 

   service的submit方法会返回一个Future<?>类型的对象,然而这是一个怎样的类型呢?让我们来看一下api中的方法摘要:

 

   

 

   从方法摘要中可以看出该对象用于在加入线程池以后能够对此任务进行取消,查看状态等操作,如果说在加入线程池以后有可能会取消此任务的话就需要,在submit的时候就需要保存好Future对象。

 

1         //保存Future<?>
2         Future<?> run2 = service.submit(runnable);
3         
4         //用于查看是否已经执行完毕,返回类型为boolean
5         System.out.println(run2.isDone());
6         
7         //取消任务,如果需要中断的话参数为true
8         run2.cancel(true);                    

 

   关于线程池的简单操作大概就有这些,关于线程池的更多信息还需要深入的研究,java的最大优点是开源,也就是说想要深入学习其原理最好的方法也就是查看源码,我也会在后面补充上线程池的源码分析,希望大家支持:-D。

 

 

原文地址:https://www.cnblogs.com/mokafamily/p/3558886.html