请详细解释Java中的线程池(ThreadPoolExecutor)的工作原理,并说明如何自定义线程池的拒绝策略

线程池(ThreadPoolExecutor)的工作原理

线程池是一种用于管理和复用线程的机制,可以有效地控制并发线程的数量,减少线程创建和销毁的开销。ThreadPoolExecutor是Java中实现线程池的核心类。

核心组件

  1. 核心线程数(corePoolSize):线程池中保持的最小线程数,即使这些线程处于空闲状态也不会被销毁。
  2. 最大线程数(maximumPoolSize):线程池中允许的最大线程数。
  3. 存活时间(keepAliveTime):当线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
  4. 工作队列(workQueue):用于保存等待执行任务的队列。
  5. 拒绝策略(RejectedExecutionHandler):当任务无法被接受时的处理策略。

工作流程

  1. 当一个任务提交到线程池时,如果当前线程数小于核心线程数,线程池会创建一个新的线程来执行任务。
  2. 如果当前线程数已经达到核心线程数,任务会被放入工作队列中等待执行。
  3. 如果工作队列已满,但当前线程数小于最大线程数,线程池会创建一个新的线程来执行任务。
  4. 如果当前线程数已经达到最大线程数,并且工作队列已满,新提交的任务将根据拒绝策略进行处理。

自定义线程池的拒绝策略

ThreadPoolExecutor提供了四种默认的拒绝策略:

  1. AbortPolicy :默认策略,抛出RejectedExecutionException异常。
  2. CallerRunsPolicy:由调用线程执行任务。
  3. DiscardPolicy:直接丢弃任务,不抛出异常。
  4. DiscardOldestPolicy:丢弃工作队列中最老的任务,然后重新尝试执行新任务。

可以通过实现RejectedExecutionHandler接口来自定义拒绝策略。以下是一个自定义拒绝策略的示例:

java 复制代码
import java.util.concurrent.RejectedExecutionHandler; 
import java.util.concurrent.ThreadPoolExecutor; 

public class CustomRejectionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("Task  " + r.toString()  + " rejected from " + executor.toString()); 
        // 可以在这里添加自定义的处理逻辑,例如记录日志、发送通知等
    }
}

使用自定义拒绝策略的示例:

ini 复制代码
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 

public class ThreadPoolExample {
    public static void main(String[] args) {
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        CustomRejectionHandler rejectionHandler = new CustomRejectionHandler();

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            workQueue,
            rejectionHandler
        );

        for (int i = 0; i < 6; i++) {
            final int taskNumber = i;
            executor.submit(()  -> {
                System.out.println("Task  " + taskNumber + " is running.");
                try {
                    Thread.sleep(2000); 
                } catch (InterruptedException e) {
                    e.printStackTrace(); 
                }
                System.out.println("Task  " + taskNumber + " is completed.");
            });
        }

        executor.shutdown(); 
    }
}

在这个示例中,我们创建了一个自定义的拒绝策略CustomRejectionHandler,并在创建ThreadPoolExecutor时将其设置为拒绝策略。当任务无法被接受时,自定义拒绝策略会打印一条消息。

总结

线程池通过管理和复用线程,提高了系统的性能和稳定性。ThreadPoolExecutor提供了灵活的配置选项和自定义拒绝策略,可以根据具体需求进行调整。

相关推荐
Olrookie29 分钟前
若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
java·前端·笔记·后端·学习·vue·ruoyi
倚栏听风雨1 小时前
java.lang.SecurityException异常
java
星河队长1 小时前
VS创建C++动态库和C#访问过程
java·c++·c#
鼠鼠我捏,要死了捏2 小时前
Java虚拟线程原理与性能优化实战
java·performance-optimization·virtual-thread
艾菜籽2 小时前
Spring MVC练习:留言板
java·spring·mvc
左灯右行的爱情2 小时前
4-Spring SPI机制解读
java·后端·spring
Code小翊2 小时前
C语言bsearch的使用
java·c语言·前端
yong99902 小时前
C#驱动斑马打印机实现包装自动打印
java·数据库·c#
好记忆不如烂笔头abc2 小时前
linux系统记录登录用户的所有操作
java·linux·服务器
sp423 小时前
一套清晰、简洁的 Java AES/DES/RSA 加密解密 API
java·后端