文章目录
更多关于Java并发编程的文章请点击这里:Java并发编程实践(0)-目录页
本文将介绍ThreadPoolExecutor的饱和策略以及ThreadPoolExecutor的扩展方法;当线程充满了ThreadPool的有界队列时,饱和策略开始起作用。饱和策略可以理解为队列饱和后,处理后续无法入队的任务的策略。在JDK中预先提供了几种饱和策略,ThreadPoolExecutor可以通过调用setRejectedExecutionHandler来修改饱和策略。ThreadPoolExecutor在设计的时候就支持扩展其方法,主要为前处理beforeExecute、后处理afterExecute`以及执行完毕处理terminated。
一、ThreadPoolExecutor的饱和策略
1.1、什么是饱和策略
当线程充满了ThreadPool的有界队列时,饱和策略开始起作用。**饱和策略可以理解为队列饱和后,处理后续无法入队的任务的策略。**在JDK中预先提供了几种饱和策略,ThreadPoolExecutor可以通过调用setRejectedExecutionHandler
来修改饱和策略。
1.2、Abort策略
ThreadPoolExecutor的 默认策略,新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。
@Test
public void testPolicy() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
5,
0,
TimeUnit.MICROSECONDS,
new ArrayBlockingQueue<Runnable>(5));
//设置饱和策略为AbortPolicy
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
//测试
for (int i = 1; i <= 11; i++) {
int count = i;
executor.execute(new Runnable() {
@Override
public void run() {
//模拟耗时操作
for (int j = 0; j < 100000; j++) {
//...
}
System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
}
});
}
}
运行后,由于设置了核心池线程数为5,有界队列能存储的线程数为5,故一共只有10个任务能被执行,多余的那1个任务将被以异常的形式抛出。
1.3、CallerRuns策略
既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,让调用者去执行它。
@Test
public void testPolicy() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
5,
0,
TimeUnit.MICROSECONDS,
new ArrayBlockingQueue<Runnable>(5));
//设置饱和策略为AbortPolicy
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//测试
for (int i = 1; i <= 11; i++) {
int count = i;
executor.execute(new Runnable() {
@Override
public void run() {
//模拟耗时操作
for (int j = 0; j < 100000; j++) {
//...
}
System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
}
});
}
}
从执行结果中可以看到,多出来的那11个任务被executor的调用者main主线程
执行。
1.4、Discard策略
多余的任务被抛弃,不执行。
@Test
public void testPolicy() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
5,
0,
TimeUnit.MICROSECONDS,
new ArrayBlockingQueue<Runnable>(5));
//设置饱和策略为DiscardPolicy
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
//测试
for (int i = 1; i <= 11; i++) {
int count = i;
executor.execute(new Runnable() {
@Override
public void run() {
//模拟耗时操作
for (int j = 0; j < 100000; j++) {
//...
}
System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
}
});
}
}
1.5、DiscardOldest策略
抛弃工作队列中的旧任务,然后尝试提交新任务执行。
@Test
public void testPolicy() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
5,
0,
TimeUnit.MICROSECONDS,
new ArrayBlockingQueue<Runnable>(5));
//设置饱和策略为DiscardOldestPolicy
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
//测试
for (int i = 1; i <= 11; i++) {
int count = i;
executor.execute(new Runnable() {
@Override
public void run() {
//模拟耗时操作
for (int j = 0; j < 100000; j++) {
//...
}
System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
}
});
}
}
从执行结果可以看出,第11个任务被执行了,说明工作队列中的最旧任务被抛弃,执行了这个新的任务。
二、ThreadPoolExecutor的扩展方法
ThreadPoolExecutor在设计的时候就支持扩展其方法,主要为前处理beforeExecute
、后处理afterExecute
以及执行完毕处理terminated
。
自定义的ThreadPoolExecutor:
public class MyThreadPoolExecutor extends ThreadPoolExecutor {
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
//before execute....
System.out.println("before execute....");
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
//after execute....
System.out.println("after execute....");
}
@Override
protected void terminated() {
super.terminated();
//terminated
System.out.println("terminated");
}
}