线程池的拒绝策略

首先线程池有以下几个参数:

1.corePoolSize:表示线程池核心大小

2.maximumPoolSize:最大线程池大小

3.keepAliveTime和unit和在一起用于指定线程池中空闲线程的最大存活空间

4.workqueue:指工作队列

5.threadFactory:用于创建工作者线程的线程工厂

6.handler:线程池饱和时,封装被拒绝任务的处理策略

此外,线程池的执行过程是这样的:

1、每过来一个任务启动一个线程去执行

2、当核心线程数用完后,会把新来的线程任务存入阻塞队列中去

3、阻塞队列存满后,在启动超过核心线程数量到最大线程数量之间的线程

4、当线程的数量达到最大线程数量时,再来任务就会启动拒绝策略

接下来我们就来具体说一下线程池的拒绝策略:

线程池的拒绝策略有以下几种:

1.ThreadPoolExector.AbortPolicy 

默认策略,丢弃任务并抛出RejectedException异常

我们能通过查看ThreadPoolExector的底层源码看到,能够创建一个默认策略,如下图:

举例说明:

public class L1 {
	
	public static void main(String[] args) {
		

        int corePoolSize=6;
		int maximumPoolSize=10;
		long keepAliveTime=6;
		
		BlockingQueue<Runnable> workqueue=new LinkedBlockingQueue<Runnable>(10);
		ThreadPoolExecutor executor=new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime,TimeUnit.MICROSECONDS, workqueue);
		RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy();
		for(int i=0;i<50;i++) {
			task myTask = new task(i);
            executor.execute(myTask);
            System.out.println("线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
                    executor.getQueue().size() + ",已执行完的任务数目:" + executor.getCompletedTaskCount());

		}
		
		

	}

}


class task implements Runnable {
    private int num;
 
    public task(int num) {
        this.num = num;
    }
 
    @Override
    public void run() {
        System.out.println("线程名称:" + Thread.currentThread().getName() + ",正在执行task " + num);
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task " + num + "执行完毕");
    }
}

 

 从图中能看到抛出了异常

2.ThreadPoolExector.DiscardPolicy

丢弃当前被拒绝的任务,且不抛出异常

public class L1 {
	
	public static void main(String[] args) {
		
		int corePoolSize=6;
		int maximumPoolSize=10;
		long keepAliveTime=6;
		BlockingQueue<Runnable> workqueue=new LinkedBlockingQueue<Runnable>(10);
		RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardPolicy();
		ThreadPoolExecutor executor=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MICROSECONDS, workqueue,handler);
		
		for(int i=0;i<50;i++) {
			task myTask = new task(i);
            executor.execute(myTask);
            System.out.println("线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
                    executor.getQueue().size() + ",已执行完的任务数目:" + executor.getCompletedTaskCount());

		}
		
		

	}
	
	

	
}


class task implements Runnable {
    private int num;
 
    public task(int num) {
        this.num = num;
    }
 
    @Override
    public void run() {
        System.out.println("线程名称:" + Thread.currentThread().getName() + ",正在执行task " + num);
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task " + num + "执行完毕");
    }
}

 从代码上跟默认策略一样,只是修改了这一句代码:

RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardPolicy();

运行之后也能看到并不像第一个拒绝策略一样报错,这个策略只是丢弃了任务但并不报错。

3.ThreadPoolExector.DiscardOldestPolicy

丢弃队列中的末尾任务(最旧的任务,也就是最早进入队列的任务)后,继续当前的任务提交给线程池

代码也只用修改一句,其他跟上面相同

RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardOldestPolicy();

 

 从执行结果来看,这个拒绝策略丢弃队列中的末尾任务继续当前的任务

4.ThreadPoolExector.CallerRunsPolicy

交给调用线程池的线程进行处理(谁调用,谁处理)

代码改动:

		RejectedExecutionHandler handler=new ThreadPoolExecutor.CallerRunsPolicy();

 以上就是线程池的四种拒绝策略。

### Java线程池拒绝策略概述 Java线程池提供了多种内置的拒绝策略来处理任务提交超出线程池容量的情况。这些策略可以通过`ThreadPoolExecutor`类进行设置,具体实现依赖于`RejectedExecutionHandler`接口。 #### 内置拒绝策略详解 1. **AbortPolicy** 默认的拒绝策略,在无法执行新任务时会抛出`RejectedExecutionException`异常[^4]。这种方式适用于希望程序立即失败并报告错误的场景。 2. **CallerRunsPolicy** 当任务被拒绝时,该策略会让提交任务的线程(即调用者线程)执行这个任务。这可能会降低系统的整体吞吐量,但在某些情况下可以缓解压力。 3. **DiscardPolicy** 静默丢弃被拒绝的任务而不做任何通知或记录。这种策略适合那些允许丢失部分任务的应用场景。 4. **DiscardOldestPolicy** 试图丢弃最旧的一个请求以便为当前任务腾出空间。此策略可能会影响较早提交的任务完成时间。 #### 自定义拒绝策略 除了上述四种标准策略外,还可以通过继承`RejectedExecutionHandler`接口来自定义拒绝逻辑。例如,`AbortPolicyWithReport`扩展了默认的`AbortPolicy`,可以在拒绝任务的同时提供额外的日志或其他操作支持[^2]。 以下是创建自定义拒绝策略的一个简单例子: ```java public class CustomRejectPolicy implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.err.println("Task " + r.toString() + " rejected from " + executor.toString()); // 可在此处添加其他处理逻辑,比如保存到队列或者日志记录 } } ``` #### 设置拒绝策略的方法 要在线程池中应用特定的拒绝策略,需在初始化`ThreadPoolExecutor`实例时指定它。下面是一个完整的示例代码片段展示如何配置带有不同拒绝策略线程池: ```java import java.util.concurrent.*; public class ThreadPoolExample { public static void main(String[] args) { int corePoolSize = 2; int maximumPoolSize = 4; long keepAliveTime = 10L; TimeUnit unit = TimeUnit.SECONDS; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2); // 创建具有CallerRunsPolicy拒绝策略线程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new ThreadPoolExecutor.CallerRunsPolicy() ); // 提交超过线程池承载能力的任务数测试效果 for (int i = 0; i < 10; i++) { final int taskNumber = i; threadPool.submit(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Executing Task " + taskNumber); }); } threadPool.shutdown(); } } ``` #### 最佳实践建议 为了更高效地利用线程池资源并减少因拒绝策略引发的问题,应遵循以下几点最佳实践: - 合理设定核心线程数(`corePoolSize`)和最大线程数(`maximumPoolSize`)以匹配实际负载需求[^3]。 - 调整阻塞队列大小(`workQueue`)以平衡内存占用与响应速度之间的关系。 - 定期监控线程池运行状况,包括活动线程计数、已完成任务总数等指标,并据此动态调整参数。 - 根据业务特点选择合适的拒绝策略;如果需要更高的灵活性,则考虑开发定制化解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值