ThreadPoolExecuor的构造方法
先来看一下ThreadPoolExecuor类的构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
参数说明:
- corePoolSize: 线程池维护线程的最少数量
- maximumPoolSize:线程池维护线程的最大数量
- keepAliveTime: 线程池维护线程所允许的空闲时间
- unit: 线程池维护线程所允许的空闲时间的单位
- workQueue: 线程池所使用的缓冲队列
- handler: 线程池对拒绝任务的处理策略
正式使用中一般都会设置一个最大缓冲队列容量,如果线程池满它会对继续添加的任务线程执行指定的拒绝策略,ThreadPoolExcetor 的最后一个参数指定了拒绝策略,JDK提供了四种拒绝策略:
- AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作。
- CallerRunsPolicy 策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。
- DiscardOleddestPolicy策略: 该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。
- DiscardPolicy策略:该策略默默的丢弃无法处理的任务,不予任何处理。
AbortPolicy策略
下面使用默认的AbortPolicy策略测试
private static ExecutorService executorService = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(Double.valueOf(10000*Math.random()).longValue());
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("i,"+Thread.currentThread().getName());
}
});
}
}
执行结果
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.gdzy.analysis.service.impl.TagServiceImpl$1@1b9e1916 rejected from java.util.concurrent.ThreadPoolExecutor@ba8a1dc[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.gdzy.analysis.service.impl.TagServiceImpl.main(TagServiceImpl.java:49)
01:40:57.795 [pool-1-thread-1] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-1
01:41:00.972 [pool-1-thread-2] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-2
可以看到,直接就抛出了异常,在执行第三次的时候
自定义拒绝策略
有时候我们需要保证任务添加不会失败,并且只要被添加的任务能依次顺序执行就好了,而不需要这个添加动作立即响应,即让线程池等待池中的任务完成后再继续添加新任务,此时JDK提供的四种策略无法满足需求,需要自定义拒绝策略,修改线程池构造方法的最后一个参数,代码如下:
private static ExecutorService executorService = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new RejectedExecutionHandler(){
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
将任务以阻塞的方式重新放回队列中,executor.getQueue().put(r)
执行结果
01:51:44.580 [pool-1-thread-1] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-1
01:51:44.580 [pool-1-thread-2] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-2
01:51:47.120 [pool-1-thread-1] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-1
01:51:50.679 [pool-1-thread-2] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-2
01:51:52.315 [pool-1-thread-1] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-1
01:51:58.987 [pool-1-thread-2] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-2
01:52:01.135 [pool-1-thread-1] INFO com.gdzy.analysis.service.impl.TagServiceImpl - i,pool-1-thread-1
可以看出,符合需求:让线程池等待池中的任务完成后再继续执行新任务,如果队列满就等待,利用了Queue put方法的阻塞。
(转载本站文章请注明作者和出处 java ThreadPoolExecutor 的使用和拒绝策略 )