Java并发编程之线程池的使用 (2)

super指向如下代码:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }

说明:newScheduledThreadPool将创建一个固定长度的线程池,而且以延迟或者定时的方式来执行任务,类似于Timer。

可以发现,以上4种方式最终都指向了ThreadPoolExecutor的以下构造函数,只是很多参数没让你指定,传递了默认值而已:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { // 省略具体的代码 }

虽然使用这4个方法可以快速的创建线程池,但还是不推荐使用,第一,很多参数都设置了默认值,不便于你理解各个参数的具体含义,第二,参数的默认值可能会造成一定的问题,最好是由使用者根据自己的需求自行指定。

那么这7个参数分别代表什么含义呢?请接着往下看。

3.2 使用ThreadPoolExecutor构造函数创建(推荐)

ThreadPoolExecutor共有以下4个构造函数,推荐使用这种方式来创建线程池:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); }

以上3个也都指向参数最全的第4个构造函数:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { // 省略具体的代码 }

以下为各个参数的讲解:

corePoolSize:核心线程数。

maximumPoolSize:最大线程数。

最大线程数=核心线程数+非核心线程数。

keepAliveTime:非核心线程闲置超时时间。

一个非核心线程,如果不干活(闲置状态)的时长超过这个参数所设定的时长,就会被销毁掉,如果设置了allowCoreThreadTimeOut = true,则会作用于核心线程。

unit:参数keepAliveTime的时间单位,如秒、分、小时。

workQueue:工作队列,即要执行的任务队列,里面存储等待执行的任务。

这里的阻塞队列可选择的有:LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、DelayedWorkQueue。

newFixedThreadPool()方法默认使用的LinkedBlockingQueue,

newCachedThreadPool()方法默认使用的SynchronousQueue,

newSingleThreadExecutor()方法默认使用的LinkedBlockingQueue,

newScheduledThreadPool()方法默认使用的DelayedWorkQueue。

threadFactory:线程工厂,用来用来创建线程。

handler:饱和策略/拒绝处理任务时的策略。

当workQueue已满,并且线程池的线程数已达到maximumPoolSize,此时新提交的任务会交由RejectedExecutionHandler handler处理,主要有以下4种策略:

AbortPolicy:中止策略,抛弃任务并抛出未检查的RejectedExecutionException,这也是默认的饱和策略。

DiscardPolicy:抛弃策略,直接抛弃任务,但不抛出异常。

DiscardOldestPolicy:抛弃最旧的策略,抛弃下一个将被执行的任务,然后尝试重新提交新的任务。

CallerRunsPolicy:调用者运行策略,将任务回退到调用者,在调用者所在的线程执行该任务。

4. 线程池的运行原理

可以通过下面2张图来理解线程池的运行原理:

Java并发编程之线程池的使用

Java并发编程之线程池的使用

1)如果线程池中的线程小于corePoolSize,则创建新线程来处理任务,这时创建的线程为核心线程。

2)如果线程中的线程等于或者大于corePoolSize,则将任务放到工作队列中,即上图中的BlockingQueue。

3)如果工作队列已满,无法将任务加入到BlockingQueue,则创建新的线程来处理任务,这时创建的线程为非核心线程,非核心线程在空闲一段时间后会被回收销毁掉(keepAliveTime和unit就是用来定义这个空闲的时间是多少)。

4)如果创建新线程导致线程池中的线程数超过了maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

5. ThreadPoolExecutor示例

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjwfw.html