ThreadPoolExecutor类

线程的创建

两种方式,一种是new一个ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

参数说明省略

另一种方式,使用Executors类中提供的几个静态工厂方法来创建线程池:

//来任务就创建线程,当线程空闲超过60秒,销毁线程。 里面调用 ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue())
Executors.newCachedThreadPool(); 
​
//创建容量为1的缓冲池,里面调用 ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue())
Executors.newSingleThreadExecutor();   
​
//创建固定容量大小的缓冲池,里面调用 ThreadPoolExecutor(int, int, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
Executors.newFixedThreadPool(int); 

但是!!!阿里巴巴Java开发手册中指出
ThreadPoolExecutor类_第1张图片

提交任务的两种方式

  • Callable
    该类任务有返回结果,可以抛出异常。
    通过submit函数提交,返回Future对象。
    可通过get获取执行结果。
  • Runnable
    该类任务只执行,无法获取返回结果,并在执行过程中无法抛异常。
    通过execute提交。

区别:submit方法内部本质上还是调用的execute方法,submit方法能用Future获取调用的返回结果。

线程的中断

shutdown():将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

shutdownNow():遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。

线程的销毁

受制于keepAliveTime。当线程不再被使用时,不会自动关闭。因此为了确保线程关闭,通过设置合理的keep-alive times,设置核心线程(core threads)数目为0或设置allowCoreThreadTimeOut(boolean)。只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0

任务队列

//无界队列,由链表实现,当线程数超过corePoolSize时,采用该队列则不会再创建线程。此时maximumPoolSize的时不会起作用。
//如果任务处理速度小于任务到达速度,采用这种队列的话,队列的长度会越来越长
LinkedBlockingQueue
​
//有界队列,由数组实现,需要考虑队列大小和最大线程池数量之间的折中。使用较长的队列和较少的最大线程池数量,会减少CPU使用、系统资源和上下文切换开销,但是吞吐量低。
//相反,使用较短的队列通常需要较大的最大线程池数量,会使CPU更忙碌但是调度开销大,也会使吞吐量降低。
ArrayBlockingQueue
​
//同步阻塞队列,该队列不储存元素。
//每个插入操作必须等到另一个线程调用移除操作
SynchronousQueue
​
//有界队列,优先级阻塞队列
PriorityBlockingQueue
​
队列吞吐量比较:
SynchronousQueue > LinkedBlockingQueue > ArrayBlockingQueue

饱和策略

当实际线程数超过最大线程数,并且阻塞队列已满时,就会调用饱和策略。

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

线程数量设置

  • CPU密集型任务
    尽量使用较小的线程池,一般为CPU核心数+1。
    因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。

  • IO密集型任务
    可以使用稍大的线程池,一般为2*CPU核心数。
    IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。

  • 最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目 http://ifeve.com/how-to-calculate-threadpool-size/

参考:
https://www.cnblogs.com/my376908915/p/6761364.html
https://zhuanlan.zhihu.com/p/33264000
https://zhuanlan.zhihu.com/p/32867181

你可能感兴趣的:(多线程)