线程池

318 阅读3分钟

概念

  • 线程池由任务队列和工作线程组成。线程执行完任务后不会退出,会继续执行新任务或阻塞等待。
  • 线程池可以管理并重用线程,控制最大并发数,避免频发创建线程的开销。
  • 任务过多时,通过排队避免创建过多线程,减少系统资源消耗和竞争,确保任务有序执行
  • 隔离线程环境,避免不同业务的线程相互影响

ThreadPoolExecutor

Executor 任务执行接口

public interface Executor {
    // 执行任务
    void execute(Runnable command);
}

ExecutorService 接口

public interface ExecutorService extends Executor {
    // 表示提交一个任务,而不是执行
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
    // 关闭任务执行,已提交的任务会继续执行,而不再接收新任务
    void shutdown();
    // 关闭任务执行, 终止已提交且未执行的任务,正在执行的任务调用interrupt方法,
    返回已提交尚未执行的任务。
    List<Runnable> shutdownNow();

}

ThreadPoolExecutor 线程池类

构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
    long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, 
    ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        // 核心线程数,设置过大会浪费资源、过小会导致线程频繁的创建或销毁
        this.corePoolSize = corePoolSize; 
        this.maximumPoolSize = maximumPoolSize; // 最大线程数
        this.workQueue = workQueue; // 任务队列
        this.keepAliveTime = unit.toNanos(keepAliveTime); // 空闲线程存活时间
        this.threadFactory = threadFactory; // 线程工厂
        this.handler = handler; // 拒绝策略
    }
实现原理
1、 有效线程数小于corePoolSize,创建新线程执行任务
2、 线程数大于核心线程数,任务会添加到任务队列
3、 如果任务队列已满,线程数小于maxPoolSize,创建新线程执行任务
4、 线程数大于最大线程数,则执行拒绝策略

当线程数大于核心线程数时,并且无任务执行则会等待keepAliveTime时间,,线程最长等待时间后仍没有任务就会被终止
任务队列 BlockingQueue

BlockingQueue 为阻塞队列接口,入队或出队需要阻塞等待。常用于生产者消费者模式。

RejectedExecutionHandler 拒绝策略

当队列有界已满且线程数大于maxPoolSize时会执行拒绝策略

ThreadPoolExecutor.AbortPolicy // 默认策略,抛出异常
ThreadPoolExecutor.CallerRunsPolicy // 任务提交线程执行任务,非线程池
ThreadPoolExecutor.DiscardOldestPolicy // 丢弃等待时间最长的任务,自己入队
ThreadPoolExecutor.DiscardPolicy // 忽略新任务

也可以自定义拒绝策略,实现RejectedExecutionHandler接口

Executors
Executors.newCachedThreadPool 高度可甚多的线程池
Executors.newFixedThreadPool 固定线程数的线程池
Executors.newScheduledThreadPool 支持定时和周期性任务执行
Executors.newSingleThreadExecutor 单线程的线程池,串行(顺序)执行任务
Executors.newWorkStealingPool

线程池的使用

  • 应根据业务场景设置合理的线程数
  • 为线程池提供有意义的名称
  • 拒绝策略应考虑业务场景
  • 线程隔离
  • 创建线程池不允许使用Executors,而应通过ThreadPoolExecutor来创建, 这样可以明确线程池的运行规则,规避资源耗尽的风险