前一篇文章写道了Executors类,其中提供了几个构造Executor的工厂方法。但在实现上,这些执行器最终都是采用了java.util.concurrent.ThreadPoolExecutor类的对象。接下来的文章我们就来了解和分析一下ThreadPoolExecutor这个类。由于篇幅比较长,这一篇主要从应用的角度,对ThreadPoolExecutor的使用做简单整理,对于任务提交和生命周期管理等源码实现的分析会在后面文章逐步整理。 0. ThreadPoolExecutor的初步认识 在之前整理Java并发开发的文章中提到,在JavaSE5之后,直接使用Thread类并不是被提倡的并发开发方式,而Executor成为主要角色。 这其中有如下几个原因:
Executors这个工具类中提供了如下静态方法:
而实际上他们是调用了ThreadPoolExecutor类的构造方法来创建Executor对象的。java.util.concurrent.ThreadPoolExecutor全参数构造方法如下:
ThreadPoolExecutor类一共有4个重载的构造方法,但最终调用的都是这个。这个构造方法的参数翠泉,一共提供了7个参数,这在Java API中的方法中,已经算是比较多的了。7个参数的简要说明如下:
更详细的解释下面会分点逐一说明。 1. 线程创建和任务提交的条件和步骤 当一个新任务被提交给ThreadPoolExecutor的时候,处理流程大概是这样的:
默认情况下,ThreadPoolExecutor的线程数是根据需求来延迟初始化的,即有新任务加进来的时候才会挨个创建线程。 除此之外,线程池执行器也提供了提前创建初始化线程的方法:
分别是预先创建一个线程和预先创建线程直到线程数到达核心线程数corePoolSize。 2. 线程数目的维护 刚刚提到,ThreadPoolExecutor有corePoolSize和maximum两个变量来维护线程池中的线程个数,提交任务的时候会有线程数目的增长,那线程的个数又是怎么来维护的呢。构造方法里还有两个参数,分别是keepAlive和unit,这两个参数确定了一个时间间隔,也就是空闲线程存活的时间间隔。默认情况下,当线程池中的线程个数超出了corePoolSize,那么空闲的线程一旦超出额定的存活时间就会被终止,以节省系统资源。在JDK1.6之后,增加了allowsCoreThreadTimeOut这个boolean属性和读写属性的方法,用来标志核心线程空闲超时是否也可以终止掉。 3. 线程入队列和任务丢弃原则简述 除了前面描述涉及到的四个属性和ThreadFactory之外,还有两个分别是workQueue和handler,分别是BlockingQueue和RejectedExecutionHandler类型。 BlockingQueue只是一个接口,它所表达的是当队列为空或者已满的时候,需要阻塞以等待生产者/消费者协同操作并唤醒线程。其有很多不同的具体实现类,各有特点。有的可以规定队列的长度,也有一些则是无界的。 按照Executors类中的几个工厂方法,分别使用的是:
当然,开发者也可以定制ThreadPoolExecutor时使用ArrayBlockingQueue有界队列。 对于任务丢弃,ThreadPoolExecutor以内部类的形式实现了4个策略。分别是:
在调用构造方法时,参数中未指定RejectedExecutionHandler情况下,默认采用AbortPolicy。 关于更多BlockingQueue、任务饱和丢弃策略和更多ThreadPoolExecutor的分析,请参见本文后面陆续整理出来的文章。 相关文章:
|
|