JAVA线程池学习以及队列拒绝策略

为什么要用线程池?

在Java中,如果每当一个请求到达就创建一个新线程,开销是相当大的。在实际使用中,每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源,甚至可能要比花在实际处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个JVM中创建太多的线程,可能会导致系统由于过度消耗内存或者“切换过度”而导致系统资源不足。为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务,这就是“池化资源”技术产生的原因。

ThreadPoolExecutor类

JDK 1.5以后,Java提供一个线程池ThreadPoolExecutor类。下面从构造函数来分析一下这个线程池的使用方法。

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

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

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

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

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

  1. CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

  2. AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException

  3. DiscardPolicy:不能执行的任务将被删除

  4. DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

Executors 工厂

ThreadPoolExecutor是Executors类的实现,Executors类里面提供了一些静态工厂,生成一些常用的线程池,主要有以下几个:

举个栗子

测试类:ThreadPool,创建了一个 newFixedThreadPool,最大线程数为3的固定大小线程池。然后模拟10个任务丢进去。主线程结束后会打印一句:主线程结束。

640?wx_fmt=png

640?wx_fmt=png

由上可见执行顺序是这样的:线程池创建了三个线程,分别执行任务0、1、2,由于线程创建需要一定时间,因此前三个线程的执行顺序具有一定随机性。此时主线程接着往线程池中塞任务,线程池已达到最大线程数(3),于是开始往队列里放。当某个线程执行完任务后,直接从队列里拉出新的任务执行,队列具有先进先出的特性,因此后面的任务执行是有序的。 这个看一下 Executors 类的源码就更明白了。

640?wx_fmt=png

实际上是创建了一个具有固定线程数、无界队列的 ThreadPoolExecutor。队列无界,不会拒绝任务提交,因此使用此方法时,需要注意资源被耗尽的情况。 测试类:TestThreadPool,采用有界队列(队列大小2),和默认拒绝策略的ThreadPoolExecutor。

640?wx_fmt=png

执行结果:

640?wx_fmt=png

线程池创建了2个线程,分别执行任务0、1,线程池达到corePoolSize,新进任务2、3被放入队列中等待处理,此时队列满,而线程池中线程没有执行完任务0、1,线程池创建新的线程,执行新进任务4、5,达到maximumPoolSize。此时所有任务都没有执行结束,主线程又继续提交任务,线程池进入默认异常策略(AbortPolicy)拒绝服务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值