自定义线程池实现
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CustomThreadPool {
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final long KEEP_ALIVE_TIME = 10;
private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
private static final BlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingQueue<>(20);
private static final ThreadFactory THREAD_FACTORY = Executors.defaultThreadFactory();
private static final RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.AbortPolicy();
private static ThreadPoolExecutor executor;
static {
executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TIME_UNIT,
WORK_QUEUE,
THREAD_FACTORY,
HANDLER);
}
public static void executeTask(Runnable task) {
executor.execute(task);
}
public static void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
拒绝策略的应用及原理
- AbortPolicy(默认):当任务提交到线程池时,如果线程池队列已满且线程数达到最大线程数,
AbortPolicy
会抛出 RejectedExecutionException
异常,拒绝接受新任务。它的原理是直接在 RejectedExecutionHandler
的 rejectedExecution
方法中抛出异常,让调用者知道任务被拒绝。
- CallerRunsPolicy:当任务被拒绝时,该策略会让调用者线程(即提交任务的线程)来执行被拒绝的任务。这样做的好处是不会丢失任务,但会影响调用者线程的性能。它的实现是在
rejectedExecution
方法中直接执行任务 r.run()
。
- DiscardPolicy:此策略会直接丢弃被拒绝的任务,不做任何处理。当应用程序可以承受丢失任务的后果时,可以使用此策略。
rejectedExecution
方法为空实现。
- DiscardOldestPolicy:该策略会丢弃队列中最老的任务(即队列头部的任务),然后尝试重新提交当前被拒绝的任务。如果队列再次满了,会再次触发拒绝策略。它的原理是先移除队列头部任务
workQueue.poll()
,然后重新尝试提交任务 execute(r)
。
不同负载情况下线程池的工作机制
- 低负载:当任务提交频率较低,任务数量小于核心线程数时,线程池会创建新线程来处理任务,每个任务对应一个线程。任务执行完毕后,线程不会立即销毁,而是保持存活,等待新任务到来,实现线程复用。
- 中等负载:随着任务提交频率增加,任务数量超过核心线程数但未达到队列容量时,新任务会被放入任务队列
WORK_QUEUE
中等待执行。核心线程处理完当前任务后,会从队列中取出新任务继续执行。
- 高负载:当任务数量超过队列容量且线程数未达到最大线程数时,线程池会创建新线程(最大到
MAX_POOL_SIZE
)来处理任务,以提高处理能力。若任务数量持续增加,达到最大线程数且队列已满,此时会根据设置的拒绝策略处理新提交的任务。
- 负载降低:当任务执行完毕,线程数超过核心线程数且在
KEEP_ALIVE_TIME
内没有新任务时,多余的线程会被销毁,线程数逐渐恢复到核心线程数,以节省资源。