在 Java 中,常见的四种线程池包括:
1.
newFixedThreadPool
(固定大小线程池)
- 应用场景:适用于需要限制线程数量,并且任务执行时间比较均匀的场景,例如服务器端的连接处理。
- 优点:线程数量固定,能够有效地控制并发线程数,避免过多的线程竞争资源。
- 缺点:如果线程在执行任务过程中出现异常导致线程终止,而新任务被提交到线程池时,可能会出现等待,直到有线程被释放。
ExecutorService executor = Executors.newFixedThreadPool(5);
示例(下面的newCachedThreadPool、newSingleThreadExecutor的使用是类似的):
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FixedThreadPoolExample { public static void main(String[] args) { // 创建一个固定大小为 5 的线程池 ExecutorService executor = Executors.newFixedThreadPool(5); // 提交 10 个任务到线程池 for (int i = 1; i <= 10; i++) { executor.execute(new Task(i)); } // 关闭线程池,不再接受新任务,但会等待已提交任务完成 executor.shutdown(); } static class Task implements Runnable { private int taskNumber; public Task(int taskNumber) { this.taskNumber = taskNumber; } @Override public void run() { System.out.println("Task " + taskNumber + " is running on thread: " + Thread.currentThread().getName()); try { // 模拟任务执行耗时 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task " + taskNumber + " is completed"); } } }
2.
newCachedThreadPool
(可缓存线程池)
- 应用场景:适用于执行很多短期异步任务的场景,例如网页服务器中的请求处理。
- 优点:可以根据需要创建新线程,如果有可用的线程则复用,能灵活应对短时间内大量的任务请求。
- 缺点:因为线程数量不固定,可能会创建大量线程,从而导致系统资源消耗过多。
ExecutorService executor = Executors.newCachedThreadPool();
3.
newSingleThreadExecutor
(单线程池)
- 应用场景:适用于需要按顺序依次执行任务的场景,例如日志记录。
- 优点:保证任务按顺序执行,避免多线程环境下的并发问题。
- 缺点:执行效率相对较低,不适合并发量大的任务。
ExecutorService executor = Executors.newSingleThreadExecutor();
4.
newScheduledThreadPool
(定时任务线程池)
- 应用场景:适用于需要执行定时任务或者周期性任务的场景,例如定时数据备份。
- 优点:能够准确地按照设定的时间间隔执行任务。
- 缺点:相对复杂,配置不当可能导致任务执行不准确。
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
示例:
package com.yuanmomo.demo.thread; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduledThreadPoolExample { public static void main(String[] args) { // 创建一个大小为 5 的定时任务线程池 ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); // 延迟 3 秒后执行一次任务 executor.schedule(new Runnable() { @Override public void run() { System.out.println("延迟任务在3秒后执行"); } }, 3, TimeUnit.SECONDS); // 每隔 2 秒执行一次任务 executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("执行周期任务"); } }, 0, 2, TimeUnit.SECONDS); // 运行一段时间后关闭线程池 try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } executor.shutdown(); } }
线程池执行流程
- 任务提交
- 当向线程池提交一个任务时,线程池会首先判断当前运行的线程数量是否小于核心线程数量。
- 如果小于,会创建一个新的线程来执行任务。
- 核心线程池已满
- 若核心线程数量已达到设定的最大值,新提交的任务会被放入任务队列中等待执行。
- 任务队列已满
- 如果任务队列已满,并且当前运行的线程数量小于最大线程数,线程池会创建新的线程来执行任务。
- 达到最大线程数
- 当线程数量达到最大线程数,并且任务队列已满时,新提交的任务会根据拒绝策略进行处理。
- 线程回收
- 当线程空闲时间超过一定限度(可设置),且当前运行线程数大于核心线程数时,多余的空闲线程会被回收。
例如:
假设线程池的核心线程数为 5,最大线程数为 10,任务队列容量为 100,拒绝策略为抛出异常。开始时,陆续提交 5 个任务,线程池会创建 5 个核心线程来执行这些任务。
接着继续提交任务,只要任务数未超过 100,新任务会被放入任务队列等待执行。
当任务队列已满,继续提交任务,此时会创建新的线程(最多到 10 个)来执行任务。
若线程数达到 10 且任务队列已满,再提交新任务,就会根据拒绝策略抛出异常。
线程来执行这些任务。
标签:Java,队列,流程,任务,线程,提交,executor,执行 From: https://blog.csdn.net/yuanmomoya/article/details/141126839接着继续提交任务,只要任务数未超过 100,新任务会被放入任务队列等待执行。
当任务队列已满,继续提交任务,此时会创建新的线程(最多到 10 个)来执行任务。
若线程数达到 10 且任务队列已满,再提交新任务,就会根据拒绝策略抛出异常。