多线程之几种不同的线程池

来源:互联网 发布:python sort 编辑:程序博客网 时间:2024/06/02 05:21

一.概括

    1.1创建线程池参数介绍

    在创建线程池时都会调用线程池的构造方法
ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue<Runnable> workQueue,                              ThreadFactory threadFactory,                              RejectedExecutionHandler handler)
    corePoolSize:线程池的核心线程数,当线程池中的工作线程数小于核心线程数的时候,只要向线程池指派任务,线程池就会创建工作线程。
    maximumPoolSize:线程池最大工作线程数,当线程池中的工作线程达到最大数的时候,即使再向线程池指派任务,线程池不会创建工作线程。
    keepAliveTime:当线程池的工作线程数大于核心线程数的时候,多余的核心线程数的部分线程可以保持keepAliveTime的空闲时间,当keepAliveTime时间内还没有获取到任务,这些线程后就会被回收。
    unit:保持空闲时间的时间单位。
    workQueue:任务队列,当线程池里面核心线程都在工作的时候,再向线程池指派任务,线程池会将任务放入任务队列里,工作线程在执行完任务后会再向任务队列里取出任务来执行。
    threadFactory:创建执行任务的工作线程。
    handler:拒绝任务加入线程池的策越,当线程池里的线程已经达到最大数后,再向线程池里加派任务时,线程池会决绝执行这些任务,handler就是具体执行拒绝的对象。
   

    1.2四种方法创建线程池

    通过Executors类可以创建四种不同的线程池

    1.newFixedThreadPool方法创建一个工作线程数一定的线程池,可以向这个线程池无限指派任务

    2.newCachedThreadPool方法创建一个工作线程不固定的线程池,这个线程池的工作线程数是灵活的,当向这个线程池指派任务的时候,线程池里如果有空闲的线程就用空闲的线程,如果没有就创建新的工作线程,理论上这个线程池的工作线程最多可以有Integer.MAX_VALUE个

    3.newSingleThreadExecutor方法创建一个只有一个工作线程的线程池,当任务来了后,该线程池可以按照任务指派的先后顺序来执行。

    4.newScheduledThreadPool方法创建一个按照一定时间周期来执行的线程池。

二、源码和例子

     1.1、newFixedThreadPoola源码     

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());    }
可以看到newFixedThreadPool方法创造出线程池的核心工作线程数和最大工作线程数的数量是一样的,这说明当线程池中的工作线程达到核心线程后,线程池中的工作线程不会再增长了。其中任务队列用的是LinkedBlockingQueue,LinkedBlockingQueue可以不用预设大小,当线程池里的工作线程都在忙碌的时候,还有多的任务就会被放入到这个阻塞队列中,理论上LinkedBlockingQueue可以无限的装入任务。

    1.2newFixedThreadPool举例   

import java.util.concurrent.Executors;import java.util.concurrent.ThreadPoolExecutor;/**  * @author  作者 wangbiao * @date 创建时间:2017年2月24日 下午4:00:30  * @parameter  * @return  */public class ThreadPoolExecutorTest {public static void main(String[] args) throws InterruptedException {          //ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 0, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));       ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);        for(int i=0;i<15;i++){            MyTask myTask = new MyTask(i);            executor.execute(myTask);            System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+            executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());        }               Thread.sleep(20000);        System.out.println("=============线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+                executor.getQueue().size()+",已执行完的任务数目:"+executor.getCompletedTaskCount());    }}class MyTask implements Runnable {    private int taskNum;         public MyTask(int num) {        this.taskNum = num;    }         @Override    public void run() {        System.out.println("正在执行task "+taskNum+"===="+Thread.currentThread().getName());        try {            Thread.currentThread().sleep(4000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("task "+taskNum+"执行完毕====="+Thread.currentThread().getName());    }}
输出结果
正在执行task 0====pool-5-thread-1线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 1====pool-5-thread-2线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 2====pool-5-thread-3线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 3====pool-5-thread-4线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 4====pool-5-thread-5线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:6,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:7,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:8,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:9,已执行玩别的任务数目:0线程池中线程数目:5,队列中等待执行的任务数目:10,已执行玩别的任务数目:0task 4执行完毕=====pool-5-thread-5task 1执行完毕=====pool-5-thread-2task 0执行完毕=====pool-5-thread-1task 2执行完毕=====pool-5-thread-3task 3执行完毕=====pool-5-thread-4正在执行task 8====pool-5-thread-3正在执行task 7====pool-5-thread-1正在执行task 6====pool-5-thread-2正在执行task 5====pool-5-thread-5正在执行task 9====pool-5-thread-4task 8执行完毕=====pool-5-thread-3task 7执行完毕=====pool-5-thread-1正在执行task 10====pool-5-thread-3正在执行task 11====pool-5-thread-1task 5执行完毕=====pool-5-thread-5task 9执行完毕=====pool-5-thread-4task 6执行完毕=====pool-5-thread-2正在执行task 13====pool-5-thread-4正在执行task 12====pool-5-thread-5正在执行task 14====pool-5-thread-2task 10执行完毕=====pool-5-thread-3task 11执行完毕=====pool-5-thread-1task 13执行完毕=====pool-5-thread-4task 12执行完毕=====pool-5-thread-5task 14执行完毕=====pool-5-thread-2=============线程池中线程数目:5,队列中等待执行的任务数目:0,已执行完的任务数目:15
当给newFixedThreadPool创建线程池设置参数为5的时候,从输出结果可以看出当向线程池指派任务的个数小于5的时候,线程池是每接受一个任务就创建一个线程,当任务大于5的时候,新来的任务就会被放到阻塞队列中。

   2.1、newCachedThreadPool源码

public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());    }

可以看出newCachedThreadPool创建线程池的时候核心线程数是0,最大线程数是Integer.MAX_VALUE,这说明当来一个线程任务,线程池就会创建一个新的工作线程,除非此时有空闲的工作线程,工作线程空闲时间是60秒,,用的阻塞队列是SynchronousQueue,对这个队列有什么特征还不是很了解。

  2.2、newCachedThreadPool举例

package threadPoolExecutor.test;import java.util.concurrent.Executors;import java.util.concurrent.ThreadPoolExecutor;/**  * @author  作者 wangbiao * @date 创建时间:2017年2月24日 下午4:00:30  * @parameter  * @return  */public class ThreadPoolExecutorTest {public static void main(String[] args) throws InterruptedException {          //ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 0, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));       //ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);ThreadPoolExecutor  executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();        for(int i=0;i<15;i++){            MyTask myTask = new MyTask(i);            executor.execute(myTask);            System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+            executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());        }               Thread.sleep(20000);        System.out.println("=============线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+                executor.getQueue().size()+",已执行完的任务数目:"+executor.getCompletedTaskCount());    }}class MyTask implements Runnable {    private int taskNum;         public MyTask(int num) {        this.taskNum = num;    }         @Override    public void run() {        System.out.println("正在执行task "+taskNum+"===="+Thread.currentThread().getName());        try {            Thread.currentThread().sleep(4000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("task "+taskNum+"执行完毕====="+Thread.currentThread().getName());    }}
输出结果
正在执行task 0====pool-1-thread-1线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 1====pool-1-thread-2线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 2====pool-1-thread-3线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 3====pool-1-thread-4线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 4====pool-1-thread-5线程池中线程数目:6,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 5====pool-1-thread-6线程池中线程数目:7,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 6====pool-1-thread-7线程池中线程数目:8,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 7====pool-1-thread-8线程池中线程数目:9,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 8====pool-1-thread-9线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 9====pool-1-thread-10线程池中线程数目:11,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 10====pool-1-thread-11线程池中线程数目:12,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 11====pool-1-thread-12线程池中线程数目:13,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 12====pool-1-thread-13线程池中线程数目:14,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 13====pool-1-thread-14线程池中线程数目:15,队列中等待执行的任务数目:0,已执行玩别的任务数目:0正在执行task 14====pool-1-thread-15task 1执行完毕=====pool-1-thread-2task 0执行完毕=====pool-1-thread-1task 2执行完毕=====pool-1-thread-3task 3执行完毕=====pool-1-thread-4task 6执行完毕=====pool-1-thread-7task 9执行完毕=====pool-1-thread-10task 5执行完毕=====pool-1-thread-6task 8执行完毕=====pool-1-thread-9task 4执行完毕=====pool-1-thread-5task 7执行完毕=====pool-1-thread-8task 14执行完毕=====pool-1-thread-15task 13执行完毕=====pool-1-thread-14task 10执行完毕=====pool-1-thread-11task 11执行完毕=====pool-1-thread-12task 12执行完毕=====pool-1-thread-13=============线程池中线程数目:15,队列中等待执行的任务数目:0,已执行完的任务数目:15
可以看出newCachedThreadPool创建的线程池,当任务来了后就会创建新的线程去执行,但是这里的情况比较极端,如果任务被很快执行了,有空的工作线程还没有被回收,这样的工作线程会被复用。

  3.1newSingleThreadPool源码

public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));    }
可以看出核心线程数和最大线程数都是一,空闲时间是0,阻塞队列用的是LinkedBlockingQueue,说明该线程池是用一个线程顺序的去执行任务。

由于举的例子不太好表现该线程池的特征,所以就不贴代码了。

 

  4.1newScheduleThreadPool举例

package threadPoolExecutor.test;import java.util.Date;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;/**  * @author  作者 wangbiao * @date 创建时间:2017年2月24日 下午4:00:30  * @parameter  * @return  */public class ThreadPoolExecutorTest {public static void main(String[] args) throws InterruptedException {         System.out.println("执行前时间:"+new Date());ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);MyTask myTask = new MyTask(1);executor.schedule(myTask, 10, TimeUnit.SECONDS);//executor.scheduleWithFixedDelay(myTask, 3, 2, TimeUnit.SECONDS);    }}class MyTask implements Runnable {    private int taskNum;         public MyTask(int num) {        this.taskNum = num;    }         @Override    public void run() {    System.out.println("执行后时间:"+new Date());        System.out.println("正在执行task "+taskNum+"===="+Thread.currentThread().getName());        try {            Thread.currentThread().sleep(0);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("task "+taskNum+"执行完毕====="+Thread.currentThread().getName());    }}
输出结果:

执行前时间:Thu Jul 06 11:34:27 CST 2017执行后时间:Thu Jul 06 11:34:37 CST 2017正在执行task 1====pool-1-thread-1task 1执行完毕=====pool-1-thread-1
可以看出任务在被延迟10秒后执行

executor.scheduleWithFixedDelay(myTask, 3, 2, TimeUnit.SECONDS);
这行代码会让任务延迟三秒执行,每两秒执行一次。




三、总结

1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。 
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务 
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理 
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程 

6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭