Executors
工厂使用无限制的待处理任务队列。例如,Executors.newFixedThreadPool
使用new LinkedBlockingQueue
,它不受接受任务的限制。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
新任务到达时,没有可用线程,它将进入队列。可以将任务无限期地添加到队列中,从而导致OutOfMemoryError
。
实际上使用这种方法的场景是什么?为什么Java创建者不使用边界队列?我无法想象无边界的情况更好,但我可能会丢失一些东西。有人可以提供一个体面的解释吗?最好!
答案 0 :(得分:3)
这是默认方法,用户可以选择更改为有界队列。
现在也许您的问题是为什么这是默认设置?
实际上很难处理有界队列,如果队列已满,您将怎么办?您放弃任务并不接受吗?您引发异常并导致整个过程失败?这不是OOM会发生的情况吗?因此,所有这些都是需要由接受大量长期运行任务的用户(不是默认的Java用户)来决定的。
无限制队列的用例可能只是当您仅期望少量正在运行的并发请求,但您不知道确切多少,或者您可以在应用程序的不同阶段实施背压,例如限制API请求
答案 1 :(得分:2)
您可以使用reject(有界阻塞队列)ArrayBlockingQueue进行任务
final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); executorService = new ThreadPoolExecutor(n, n, 0L, TimeUnit.MILLISECONDS, queue);
上面的代码等效于Executors.newFixedThreadPool(n),但是我们使用固定容量为100的ArrayBlockingQueue代替了默认的无限LinkedBlockingQueue,这意味着如果已将100个任务排队(并且正在执行n),则将执行新任务被RejectedExecutionException拒绝。
答案 2 :(得分:1)
可以无限期将任务添加到队列中,从而导致OutOfMemoryError
不。队列并不是真正的unbouned
,对于无界的LinkedBlockingQueue
,它的capacity
是Integer.MAX_VALUE(2147483647)
。如果没有足够的空间,RejectedExecutionHandler
将处理新的到达任务。默认处理程序为AbortPolicy
,它将直接中止新任务。
我无法想象无界的情况更好。
用户可能不在乎队列大小,或者只是不想限制缓存的任务。
如果您确实关心它,则可以使用自定义构造函数创建一个ThreadPoolExecutor
。
答案 3 :(得分:1)
由于您正在询问“用例”,因此非常简单:每次您有很多单个任务要最终完成。假设您要下载数十万个文件?为每个创建一个下载任务,提交给ExecutorService
,等待终止。由于您无需再添加任何内容,因此这些任务最终将完成,并且没有限制的理由。