ThreadPoolExecutor 创建线程池

 ThreadPoolExecutor 创建线程池 

/**
 * public ThreadPoolExecutor(
 *     int corePoolSize,                    //--线程池核心池的大小。
 *     int maximumPoolSize,                 //--线程池的最大线程数。
 *     long keepAliveTime,                  //--当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
 *     TimeUnit unit,                       //--keepAliveTime(线程存活时间) 的时间单位。
 *     BlockingQueue<Runnable> workQueue,   //--用来储存等待执行任务的队列。
 *     ThreadFactory threadFactory,         //--线程工厂。
 *     RejectedExecutionHandler handler     //--拒绝策略。
 * )
 */

a、 线程池大小

1、线程池有两个线程数的设置,一个为核心池线程数,一个为最大线程数。
2、在创建了线程池后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务,除非调用了                prestartAllCoreThreads()或者prestartCoreThread()方法
3、当创建的线程数等于 corePoolSize 时,会加入设置的阻塞队列。当队列满时,会创建线程执行任务直到线程池中的数量等于maximumPoolSize。

b、 适当的阻塞队列

线程池中任务有三种排队策略:

1、直接提交。直接提交策略表示线程池不对任务进行缓存。新进任务直接提交给线程池,当线程池中没有空闲线程时,创建一个新的线程处理此任务。这种策略需要线程池具有无限增长的可能性。实现为:SynchronousQueue

2、有界队列。当线程池中线程达到corePoolSize时,新进任务被放在队列里排队等待处理。有界队列(如ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。

3、无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

java.lang.IllegalStateException: Queue full
方法 抛出异常 返回特殊值 一直阻塞 超时退出
插入方法 add(e) offer(e) put(e) offer(e,time,unit)
移除方法 remove() poll() take() poll(time,unit)
检查方法 element() peek() 不可用 不可用

ArrayBlockingQueue       --一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue     --一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue    --一个支持优先级排序的无界阻塞队列。
DelayQueue                   -- 一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue        -- 一个不存储元素的阻塞队列。
LinkedTransferQueue     -- 一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque     -- 一个由链表结构组成的双向阻塞队列。

c、 明确拒绝策略

拒绝策略:当任务源源不断的过来,而我们的系统又处理不过来的时候,我们要采取的策略是拒绝服务。RejectedExecutionHandler接口提供了拒绝任务处理的自定义方法的机会。

在ThreadPoolExecutor中已经包含四种处理策略。

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

1、AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException();}
这种策略直接抛出异常,丢弃任务。(jdk默认策略,队列满并线程满时直接拒绝添加新任务,并抛出异常,所以说有时候放弃也是一种勇气,为了保证后续任务的正常进行,丢弃一些也是可以接收的,记得做好记录)

2、DiscardPolicy:不能执行的任务将被删除
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}
这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。

3、DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) {e.getQueue().poll();e.execute(r); }}
该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。这个策略需要适当小心。

4、CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); }}
这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。(开始我总不想丢弃任务的执行,但是对某些应用场景来讲,很有可能造成当前线程也被阻塞。如果所有线程都是不能执行的,很可能导致程序没法继续跑了。需要视业务情景而定吧。)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值