Java ThreadPoolExecutor [Submit More Than MaxPoolSize]

huangapple go评论79阅读模式
英文:

Java ThreadPoolExecutor [Submit More Than MaxPoolSize]

问题

我有一个应用程序,允许用户批量给图像添加水印。该应用程序仅使用一个线程,并且一次只能添加一个水印。

我希望用户能够在设置中更改同时运行的水印任务(线程)的数量:可能是1-5个,但我不能使用固定大小的线程池,因为它具有固定的池大小。

我查看了使用ThreadPoolExecutor的方法:

private static ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();

每当用户更改线程数时,我调用ThreadPoolExecutor.setMaxPoolSize(newMaxThreadCount)。

现在,当我尝试将15个图像水印任务提交给具有最大池大小为3的执行器时,
我会得到以下异常:

java.util.concurrent.RejectedExecutionException: Task com.darkmental.zeondownloader.app.main.phototools.watermark.BulkWatermarkTask$$Lambda$710/1861585081@1e2d8ad4 被拒绝,来自java.util.concurrent.ThreadPoolExecutor@24d02747[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]

我期望ThreadPoolExecutor具有与fixedThreadPool相同的行为,即我可以具有池大小为10,并且仍然可以提交任意数量的任务,但实际情况不是这样。我该如何做?

英文:

I have an app that allows users to batch add watermarks to images. The app would only use one thread and can only add one watermark at a time.

I want the user to be able to change the number of watermark tasks[threads] running at a time: maybe [1-5] in settings, and I can't use a fixedThreadPool, as it has a fixed pool size.

I looked into using a ThreadPoolExecutor private static ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); and each time the user changes the number of threads I invoke the ThreadPoolExecutor.setMaxPoolSize(newMaxThreadCount).

Now when I try to submit say 15 image watermark tasks to the executor with a maximum pool size of 3,
I get the following exception:

> java.util.concurrent.RejectedExecutionException: Task com.darkmental.zeondownloader.app.main.phototools.watermark.BulkWatermarkTask$$Lambda$710/1861585081@1e2d8ad4 rejected from java.util.concurrent.ThreadPoolExecutor@24d02747[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]

I expected the ThreadPoolExecutor to have the same behavior as a fixedThreadPool where I can have a pool size of 10 and still submit as many tasks as I want, but I didn't. How can I do that?

答案1

得分: 3

查看JavaDoc,可以看出这种行为是有意的。

> 在使用方法execute(java.lang.Runnable)提交新任务时,当执行器已关闭,并且执行器对最大线程数和工作队列容量都使用有限边界且饱和时,任务将被拒绝。

所以在你的情况下,你的队列似乎已满或不接受新项目。
我还没有看到你实际是如何创建ThreadPoolExecutor的,但我猜想你需要在构造函数中指定一个足够大的BlockingQueue

**编辑:**这可能是因为Executors.newCachedThreadPool()是无界的,并且在没有可用的缓存线程时每次都会创建一个新线程。但是,设置最大池大小会干扰这一点,并且任务会通过RejectedExecutionHandler被拒绝。

我目前无法重现这种情况,但你可能可以通过setRejectedExecutionHandler(ThreadPoolExecutor.CallerRunsPolicy)将活动的AbortPolicy更改为ThreadPoolExecutor.CallerRunsPolicy,这将导致调用线程执行新任务,而不是抛出异常。

英文:

A look at the JavaDoc shows, that this behaviour is intended.

> New tasks submitted in method execute(java.lang.Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated.

So in your case, your queue seems to be full or doesn't accept any new items.
I haven't seen how you actually created your ThreadPoolExecutor, but I would guess, that you need to specify a sufficent BlockingQueue in the constructor.

EDIT: This probably happens, because Executors.newCachedThreadPool() is unbounded and creates a new Thread every time, if there is no cached Thread available. However setting the maximum pool size interferes with this and the task is rejected via the RejectedExecutionHandler.

I currently can't reproduce the scenario, but you probably can change the active AbortPolicy to ThreadPoolExecutor.CallerRunsPolicy via setRejectedExecutionHandler(ThreadPoolExecutor.CallerRunsPolicy). This result in the calling Thread to execute the new tasks instead of throwing an Exception.

huangapple
  • 本文由 发表于 2020年10月19日 05:16:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/64418418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定