如何让ThreadPool在有可用线程时提交任务以避免资源耗尽
解决线程池任务无限制堆积的问题
你这段代码的核心问题在于无限制地向线程池提交任务——线程池只有2个工作线程,但你每次循环就提交500个任务,这些未执行的任务会不断积压在线程池的无界队列中,随着循环次数增加,队列占用的内存会越来越大,最终导致程序资源耗尽甚至崩溃。
要实现「仅在线程池有可用线程时才提交任务」的需求,最可靠的方式是用Semaphore(信号量)做流量控制,让提交任务的速度和线程池的处理能力匹配。具体思路如下:
- 创建一个许可数等于线程池大小的信号量
- 每次提交任务前,先获取一个信号量许可(没有可用许可时会阻塞,直到有线程空闲)
- 任务执行完成后,释放对应的许可,让新的任务可以被提交
下面是修改后的完整代码:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class ControlledTaskSubmission { public static void main(String[] args) { int threadPoolSize = 2; ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize); // 信号量许可数与线程池大小保持一致 Semaphore taskSemaphore = new Semaphore(threadPoolSize); int iteration = 1; while (true) { for (int i = 0; i < 500; i++) { try { // 阻塞等待可用许可,直到有线程释放资源 taskSemaphore.acquire(); System.out.println("Exec " + iteration + " " + i); executorService.execute(new Runnable() { @Override public void run() { try { System.out.println("entered"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 任务执行完毕,必须释放许可,否则会导致信号量耗尽 taskSemaphore.release(); } } }); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Finished iteration " + iteration++); } } }
关键细节说明
- 信号量的
acquire()方法会阻塞当前线程,直到获取到可用许可——这就保证了只有线程池有空闲线程时,才会提交新任务 - 必须在
finally块中调用release(),确保即使任务执行抛出异常,许可也能被正确释放,避免信号量被永久占用 - 这种方式从根源上避免了任务堆积,线程池的队列不会出现大量未执行的任务,内存占用会保持稳定
内容的提问来源于stack exchange,提问作者Vml11
相关产品推荐
相关产品推荐

