1 线程池有什么用
①节省系统资源:频繁地创建和销毁线程会消耗系统资源,线程池能够复用已创建的线程。
②提高响应速度:当任务到达时,任务可以不需要等待线程创建就立即执行。
【比如】当用户发起一个实时请求,服务器需要快速响应,此时如果每次请求都直接创建一个线程,那么线程的创建和销毁会消耗大量的系统资源。使用线程池,可以预先创建一定数量的线程,当用户请求到来时,直接从线程池中获取一个空闲线程,执行用户请求,执行完毕后,线程不销毁,而是继续保留在线程池中,等待下一个请求。
③除此之外,线程池支持定时执行、周期性执行、单线程执行和并发数控制等功能。
2 线程池工作流程
当应用程序提交一个任务时,线程池会根据当前线程的状态和参数决定如何处理这个任务。
如果当前线程数量小于核心线程数,线程池会直接创建一个新的线程来执行这个任务;
如果线程池中的核心线程都在忙,但任务队列未满,新提交的任务会被放入队列中进行等待;
如果任务队列已满,但当前线程数量小于最大线程数,线程池会创建新的线程来处理任务;
如果任务队列已满,且当前线程数量达到最大线程数,则线程池执行拒绝策略;
当某个任务执行完毕后,线程并不会立即销毁,而是继续保持在池中等待下一个任务;
当线程空闲时间超出指定时间,且当前线程数大于核心线程数时,线程会被回收。
3 线程池主要参数
// 线程池主要参数有 7 个
ExecutorService threadPool = new ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize,// 最大线程数
long keepAliveTime,// 线程空闲时间(非核心线程空闲存活时间)
TimeUnit unit,// 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory,// 线程工厂
RejectedExecutionHandler handler// 拒绝策略
);
① corePoolSize 和 maximumPoolSize 共同定义了线程池的规模。
当提交的任务数不足以填满核心线程时,线程池只会创建足够的线程来处理任务。
当任务数增多,超过核心线程的处理能力时,任务会被加入 workQueue。
如果 workQueue 已满,而当前线程数又小于 maximumPoolSize,线程池会尝试创建新的线程来处理任务。
② keepAliveTime 和 unit 决定了非核心线程可以空闲存活多久。这会影响了线程池的资源回收策略。
③ workQueue 的选择对线程池的行为有影响。不同类型的队列(如无界队列、有界队列)会导致线程池在任务增多时的反应不同。
④ handler 定义了线程池的饱和策略,即当线程池无法接受新任务时的行为。决定了系统在极限情况下的表现。
3 线程池的阻塞队列有哪些实现方式?
① ArrayBlockingQueue:一个有界的先进先出阻塞队列,底层是一个数组,适合固定大小的线程池。
② LinkedBlockingQueue:底层数据结构是链表,默认大小是 Integer.MAX_VALUE,相当于一个无界队列。
Executors.newSingleThreadExecutor() (单线程的线程池) 和 Executors.newFixedThreadPool()(固定线程数目的线程池) 都使用了该队列,前者适用于串行执行任务的场景,后者适用执行长期的任务。
③ PriorityBlockingQueue:一个支持优先级排序的无界队列。任务按照其自然顺序或通过构造器给定的 Comparator 来排序。适用于需要按照给定优先级处理任务的场景,比如优先处理紧急任务。
④ DelayQueue:类似于 PriorityBlockingQueue,由二叉堆实现的无界优先级队列。
Executors.newScheduledThreadPool()(定时及周期执行的线程池) 就使用了该队列来实现延迟执行,适合周期性执行任务的场景。
⑤ SynchronousQueue:不是一个真正的队列,因为没有容量。每个插入操作必须等待另一个线程的移除操作。
Executors.newCachedThreadPool()(可缓存线程的线程池) 就使用了该队列,核心线程数为 0,这个线程池会根据需要创建新线程,如果有空闲线程则会重复使用,线程空闲 60 秒后会被回收。适用于并发执行大量短期的小任务。
4 线程池的四种拒绝策略
AbortPolicy:这是 默认 的拒绝策略。该策略会抛出一个 RejectedExecutionException 异常。
CallerRunsPolicy:该策略不会抛出异常,而是会让提交任务的线程(即调用 execute 方法的线程)自己执行这个任务。
DiscardOldestPolicy:丢弃队列中最老的一个任务(即队列中等待最久的任务),然后尝试重新提交被拒绝的任务。
DiscardPolicy:丢弃该被拒绝的任务,不做任何处理也不抛出异常。【太坏了】
【如有错误或补充见解,欢迎留言交流和指正】