提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
面对自动创建线程会面临的诸多像线程创建启动过多,核心线程数量使用完后对于后续线程的加入,线程池提供了四种拒绝策略,为了便于后续学习,我对其做了一些简单的总结。
一、线程池是什么?
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。而线程拒绝策略则是线程管理线程,防止线程运行过多而采取的一种管理策略。
二、测试展示:
为了提高线程的可靠性,Java标准类库引入了一个**RejectedExecutionHandler**接口,用于封装被拒绝任务的处理策略。可以通过线程池的构造器参数**handler**,或者**setRejectedExecutionHandler**方法来为线程池关联一个**RejectedExecutionHandler。**
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);handler:线程池饱和时,封装被拒绝任务的处理策略 抽象方法:abstract void rejectedExecution(Runnable r,ThreadPoolExecutor executor); r代表被拒绝的任务,executor代表拒绝任务r的线程池实例。
1.关于RejectedExecutionHandler操作说明
1. 当客户端提交的任务被拒绝时,线程池所关联的RejectedExecutionHandler的
rejectedExecution方法会被线程池调用。
2.ThreadPoolExecutor自身提供了几个现成的RejectedExecutionHandler
接口的实现类。其中ThreadPoolExecutor.AbortPolicy是
ThreadPoolExecutor使用的默认RejectedExecutionHandler。
3. 如果默认的RejectedExecutionHandler(它会直接抛出异常)无法满足要求,
那么我们可以优先考虑ThreadPoolExecutor自身提供的其他
RejectedExecutionHandler,其次才去考虑使用自身实现的
RejectedExecutionHandler接口。
2.其他实现类的表现:
实现类 所实现的处理策略 ThreadPoolExecutor.AbortPolicy 直接抛出异常 ThreadPoolExecutor.DiscardPolicy 丢弃当前被拒绝的任务(而不抛出任何异常) ThreadPoolExecutor.DiscardOldestPolicy 将工作队列中最老的任务丢弃,然后重新 尝试接纳被拒绝的任务 ThreadPoolExecutor.CallerRunsPolicy 在客户端线程中执行被拒绝的任务
*/
1.AbortPoilcy( 直接抛出异常):
测试代码
public static void main(String[] args) throws Exception{
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 5;
//创建阻塞队列队列为10
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(10);
//调用AbortPoilcy
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
//创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, handler);
Runnable r = () -> System.out.println(Thread.currentThread().getName() + " is running");
for(int i=0; i<100; i++) {
try {
executor.execute(r);
} catch (Exception e) {
e.printStackTrace();
}
}
//关闭线程池
executor.shutdown();
}
运行结果展示
使用execute()提交任务,会抛出运行期异常,java.util.concurrent.RejectedExecutionException:如果没有执行异常抛出的话,不会执行一百次线程,可自行测试下,很容易在控制台console中能查看到。
2.DiscardPolicy(丢弃当前被拒绝的任务(而不抛出任何异常))
当任务添加到线程池中被拒绝时,默认情况下它将丢弃被拒绝的任务。(即该策略下,直接丢弃任务,什么都不做)
//同上,只给出要修改的部分,其他测试主题不变
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
运行结果展示:
可以看到旁边是没有滚动条,所以,显而易见的,他并没有一百条线程执行结果,有一部分被直接进行丢弃,也没有抛出异常,
** 3、DiscardOldestPolicy()**
DiscardOldestPolicy策略的作用是,当任务被拒绝添加时,会抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
运行结果展示
从上面运行结果控制台上的滚动条展示效果,也没有达到一百条运行结果,所以,这种拒绝策略也进行了线程的拒绝,
4、CallerRunsPolicy(在客户端线程中执行被拒绝的任务)
//,只需要将拒绝策略代码改为,主体代码不变。查看运行结果
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
运行结果如下:
运行后,在控制台console中能够看到的是,会有一部分的数据打印,显示的是 “main is running”,
总结
线程池的构造函数中所表现的,拒绝策略是一种管理线程运行的策略,对当前线程的调度,对后续线程的接受和使用,现场城池的高效,有很大一部分是由线程池的拒绝策略实现的,四种拒绝策略是相互独立无关的,选择何种策略去执行,还得结合具体的场景。实际工作中,一般直接使用 ExecutorService 的时候,都是使用的默认的 defaultHandler ,也即 AbortPolicy 策略。
版权归原作者 来日方长。。。。long 所有, 如有侵权,请联系我们删除。