线程池(ThreadPoolExecutor)的工作原理
线程池是一种用于管理和复用线程的机制,可以有效地控制并发线程的数量,减少线程创建和销毁的开销。ThreadPoolExecutor
是Java中实现线程池的核心类。
核心组件:
- 核心线程数(corePoolSize):线程池中保持的最小线程数,即使这些线程处于空闲状态也不会被销毁。
- 最大线程数(maximumPoolSize):线程池中允许的最大线程数。
- 存活时间(keepAliveTime):当线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
- 工作队列(workQueue):用于保存等待执行任务的队列。
- 拒绝策略(RejectedExecutionHandler):当任务无法被接受时的处理策略。
工作流程:
- 当一个任务提交到线程池时,如果当前线程数小于核心线程数,线程池会创建一个新的线程来执行任务。
- 如果当前线程数已经达到核心线程数,任务会被放入工作队列中等待执行。
- 如果工作队列已满,但当前线程数小于最大线程数,线程池会创建一个新的线程来执行任务。
- 如果当前线程数已经达到最大线程数,并且工作队列已满,新提交的任务将根据拒绝策略进行处理。
自定义线程池的拒绝策略
ThreadPoolExecutor
提供了四种默认的拒绝策略:
- AbortPolicy :默认策略,抛出
RejectedExecutionException
异常。 - CallerRunsPolicy:由调用线程执行任务。
- DiscardPolicy:直接丢弃任务,不抛出异常。
- 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
提供了灵活的配置选项和自定义拒绝策略,可以根据具体需求进行调整。