线程池
线程池也是一种多线程模式,特点在于可以根据需求创建线程池,线程池的线程直接执行任务。
线程池的优点🎯
复用:线程与任务是分离的,所以一个线程可以执行多个任务。
资源: 线程池中的线程一直处于RUNNABLE状态去获取任务,不会立即被销毁,减少了创建和销毁线程带来的资源开销。
可管理: 线程池会根据任务再去创建或者销毁线程,避免大量的线程被创建和销毁。
速度: 由于线程已经准备好了,只要有任务线程就可以立即执行,减少了创建和启动的时间。
创建线程池🎯
Java标准库提供了创建线程池的接口Executers,它只是用来创建线程池,而线程池的接口是ExecuterService。Executors类里面提供了一些静态工厂,生成一些常用的线程池。
// 1. 可以缓存线程的线程池,用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将收回并移出缓存
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 2. 创建一个操作无界队列(LinkedBlockingQueue)且固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(n);
// 3. 创建一个操作无界队列且只有一个工作线程的线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 4. 创建一个单线程执行器,可以在给定时间后执行或定期执行。
ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor类(Executor的子类)实现的。
ThreadPoolExecutor创建线程池,它的构造方法提供了很多参数,可以自定义的设置想要的线程池。它提供了四种构造方法,下面是最全参数的一种,其他三种只是最后两个参数区别。
ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize,// 最大线程数
long keepAliveTime, // 非核心线程的空闲存活时间
TimeUnit unit, // 存活时间的计量单位
BlockingQueue<Runnable> workQueue, // 组织任务的阻塞队列
ThreadFactory threadFactory, // 辅助创建线程的线程工厂
RejectedExecutionHandler handler // 执行任务失败处理器,拒绝策略
)
RejectedExecutionHandler拒绝策略是指线程池满了,那么继续添加任务采取的拒绝方法
。拒绝策略也提供了四种:
ThreadPoolExecutor.AbortPolicy // 直接抛出异常
ThreadPoolExecutor.CallerRunsPolicy // 哪个线程添加的则哪个线程执行这个任务
ThreadPoolExecutor.DiscardOldestPolicy // 把队列中最老(最先入队)的任务丢弃
ThreadPoolExecutor.DiscardPolicy // 丢弃这个添加的任务(最新)
线程池的工作流程🎯
模拟实现线程池🎯
模拟一个设置固定大小的线程池
class ThreadPool{
// 组织任务
private BlockingDeque<Runnable> blockingDeque = new LinkedBlockingDeque<>();
// 添加任务
public void submit(Runnable runnable) throws InterruptedException {
blockingDeque.put(runnable);
}
// 设置线程池
public ThreadPool(int n) {
for(int i = 0;i < n;i++) {
// 每个线程的任务是一直从阻塞队列获取任务,拿到就执行。
Thread t = new Thread(() -> {
while (true) {
try {
Runnable runnable = blockingDeque.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
}