外观
SingleThreadPollExecutor 是什么?
⭐ 题目日期:
京东 - 2024/12/26
📝 题解:
SingleThreadExecutor
是 Java 中通过 Executors
工具类提供的一种单线程的线程池,底层基于 ThreadPoolExecutor
实现。它保证所有任务按提交顺序依次执行,且在任何情况下(包括线程异常退出)仅有一个工作线程存活,适合需要严格顺序执行任务的场景。
核心特性
- 单线程执行
无论提交多少任务,始终只有一个工作线程处理任务,天然线程安全。 - 自动重建线程
若线程因异常终止,线程池会自动创建新线程继续执行后续任务。 - 无界任务队列
默认使用LinkedBlockingQueue
(容量为Integer.MAX_VALUE
),任务可无限堆积,需警惕内存溢出(OOM)。
创建方式
通过 Executors.newSingleThreadExecutor()
工厂方法创建:
ExecutorService executor = Executors.newSingleThreadExecutor();
底层实际是配置好的 ThreadPoolExecutor
:
new ThreadPoolExecutor(
1, // 核心线程数 = 1
1, // 最大线程数 = 1
0L, // 空闲线程存活时间(无意义,因核心线程数=最大线程数)
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>() // 无界队列
);
适用场景
- 任务需严格顺序执行
例如:日志顺序写入、事件队列处理。 - 避免多线程竞争开销
单线程无锁操作,简化并发控制。 - 替代手动管理单线程
利用线程池的任务队列和生命周期管理功能。
示例代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交10个任务
for (int i = 0; i < 10; i++) {
int taskId = i;
executor.execute(() -> {
System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");
if (taskId == 5) {
throw new RuntimeException("模拟任务异常"); // 线程异常终止后,线程池会重建新线程
}
});
}
executor.shutdown(); // 关闭线程池
}
}
输出:
任务 0 由线程 pool-1-thread-1 执行
任务 1 由线程 pool-1-thread-1 执行
...
任务 5 由线程 pool-1-thread-1 执行
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 模拟任务异常
任务 6 由线程 pool-1-thread-2 执行 // 异常后自动重建线程
任务 7 由线程 pool-1-thread-2 执行
...
注意事项
避免无界队列内存溢出
默认使用无界队列(LinkedBlockingQueue
),若任务提交速度远快于处理速度,可能导致OutOfMemoryError
。
解决方案:自定义ThreadPoolExecutor
,改用有界队列并设置拒绝策略。异常处理
任务抛出的异常会导致线程终止,但线程池会自动重建线程。可通过以下方式捕获异常:executor.submit(() -> { try { // 任务代码 } catch (Exception e) { e.printStackTrace(); } });
或使用
Future
获取异常信息:Future<?> future = executor.submit(task); try { future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
关闭线程池
使用shutdown()
平滑关闭,或shutdownNow()
强制终止未执行任务。
与手动创建单线程的区别
对比项 | SingleThreadExecutor | 手动创建 Thread |
---|---|---|
任务队列管理 | 支持任务缓冲,避免资源耗尽 | 需自行实现队列逻辑 |
线程重建 | 自动重建异常终止的线程 | 需手动捕获异常并重启线程 |
生命周期管理 | 提供统一的关闭接口 | 需手动控制线程启停 |
总结
SingleThreadExecutor
是一种简单但强大的线程池,适用于需要顺序执行任务且希望减少并发复杂性的场景。通过合理使用,既能简化代码,又能利用线程池的自动管理能力,避免手动操作单线程的繁琐和潜在风险。