在 Java 中,ExecutorService 本身是为了解耦任务提交与执行、避免直接阻塞调用线程而设计的,但如果使用不当,仍然会出现阻塞、线程耗尽、拒绝任务等问题。下面从常见阻塞场景和避免策略两个角度说明。
submit() + Future.get() 无超时Future<?> f = executor.submit(task);
f.get(); // 可能永久阻塞
✅ 问题:get() 会一直等任务完成。
invokeAll() / invokeAny()executor.invokeAll(tasks); // 阻塞直到全部完成
✅ 会阻塞调用线程。
new ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>() // 无限队列
);
✅ 任务堆积,消费跟不上,导致内存压力或响应变慢。
executor.execute(() -> {
socket.read(); // 阻塞线程
});
✅ 线程被占住,线程池“看起来”卡死。
Future.get() 设置超时try {
future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
}
CompletableFuture(非阻塞)CompletableFuture.runAsync(task, executor)
.thenRun(() -> log.info("done"))
.exceptionally(ex -> {
log.error("error", ex);
return null;
});
✅ 不阻塞调用线程,支持回调。
new ThreadPoolExecutor(
10,
50,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy()
);
要点:
CallerRunsPolicy:调用线程执行,天然限流AbortPolicy:快速失败❌ 错误:
executor.submit(this::doWork).get();
✅ 正确:
executor.submit(() -> {
doWork();
notifyComplete();
});
ExecutorService ioExecutor =
Executors.newFixedThreadPool(100);
ExecutorService cpuExecutor =
Executors.newWorkStealingPool();
✅ 避免 IO 阻塞影响 CPU 任务。
CompletionService 取已完成任务CompletionService<String> cs =
new ExecutorCompletionService<>(executor);
for (Callable<String> task : tasks) {
cs.submit(task);
}
for (int i = 0; i < tasks.size(); i++) {
Future<String> f = cs.take(); // 只等最快完成的
}
✅ 不要在业务线程里等 Future
✅ 使用有界队列 + 合理拒绝策略
✅ IO / CPU 任务线程池分离
✅ 优先 CompletableFuture / 回调
✅ 所有阻塞操作都要有超时
如果你有具体场景(Web 请求、批量任务、定时任务等),我可以给你更针对性的线程池配置示例。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。