Java:SingleThreadScheduledExecutor & java.util.concurrent.RejectedExecutionException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1937942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: SingleThreadScheduledExecutor & java.util.concurrent.RejectedExecutionException
提问by Andrey
I am having this problem, I have
我有这个问题,我有
private ScheduledExecutorService executor =
Executors.newSingleThreadScheduledExecutor();
and task which is created every 50 millliseconds:
和每 50 毫秒创建一次的任务:
executor.scheduleAtFixedRate(myTask, 0, 50, TimeUnit.MILLISECONDS);
myTasksometimes take a while to complete (like 2-3 seconds or so), but newSingleThreadScheduledExecutor guarantees that next scheduled myTask will wait until the current one completes.
myTask有时需要一段时间才能完成(比如 2-3 秒左右),但 newSingleThreadScheduledExecutor 保证下一个预定的 myTask 将等到当前一个完成。
However, I get this error from time to time:
但是,我不时收到此错误:
execute: java.util.concurrent.RejectedExecutionException
执行: java.util.concurrent.RejectedExecutionException
What should I do? Thanks
我该怎么办?谢谢
回答by skaffman
Consider what the executor is doing. It is running a single task every 50 milliseconds, as per your instructions. Assuming this task takes less than 50 milliseconds to run, then everything is fine. However, every so often it takes 2-3 seconds to run. When this happens, the executor still tries to execute every 50 milliseconds, but because it only has a single thread, it can't, and rejects those executions that are being triggered while your long-running task is still going. This causes the exception you see.
考虑执行者在做什么。根据您的指示,它每 50 毫秒运行一个任务。假设这个任务的运行时间少于 50 毫秒,那么一切都很好。但是,每隔一段时间运行一次就需要 2-3 秒。发生这种情况时,执行器仍会尝试每 50 毫秒执行一次,但因为它只有一个线程,所以不能,并拒绝那些在长时间运行的任务仍在执行时触发的执行。这会导致您看到的异常。
You have two choices to fix this (assuming you want to stick with a single thread):
您有两种选择来解决这个问题(假设您想坚持使用单个线程):
Use
scheduleWithFixedDelayrather thanscheduleAtFixedRate. If you read the javadoc carefully, you'll see thatscheduleWithFixedDelaywill wait 50 milliseconds between the finishing of one task and the start of the next, so it will never "overlap", even if one of them takes a long time. In contrast,scheduleAtFixedRatewill try to execute every 50 milliseconds, regardless of how long each one takes.Change the way that the executor handles failures to execute. The default is to log an exception, but you can tell it to ignore it, for example. Take a look at the subclasses of of
java.util.concurrent.RejectedExecutionHandler, for exampleDiscardPolicy, which just silently drops the task that can't be run. You can use these by directly constructingScheduledThreadPoolExecutorand passing in the handler to the constructor, rather than using theExecutorsfactory class.
使用
scheduleWithFixedDelay而不是scheduleAtFixedRate. 如果您仔细阅读 javadoc,您会发现scheduleWithFixedDelay在完成一项任务和开始下一项任务之间将等待 50 毫秒,因此它永远不会“重叠”,即使其中一项需要很长时间。相比之下,scheduleAtFixedRate将尝试每 50 毫秒执行一次,而不管每个执行需要多长时间。改变执行器处理执行失败的方式。默认是记录一个异常,但你可以告诉它忽略它,例如。看看 的子类
java.util.concurrent.RejectedExecutionHandler,例如DiscardPolicy,它只是默默地丢弃无法运行的任务。您可以通过直接构造ScheduledThreadPoolExecutor处理程序并将其传递给构造函数来使用这些,而不是使用Executors工厂类。
I suspect option (1) is what you want.
我怀疑选项 (1) 是您想要的。
回答by Dean Povey
This exception will be thrown when either:
在以下任一情况下将抛出此异常:
- You have shutdown the Executor
- The Executor's bounds for its work queue or maximum threads have been exceeded.
- 你已经关闭了 Executor
- 已超出 Executor 的工作队列或最大线程数的界限。
I assume the latter is happening. When you execute your task and it takes a long time then subsequent scheduled tasks can not be run because there are not enough threads available in the pool.
我认为后者正在发生。当您执行任务并且需要很长时间时,随后的计划任务将无法运行,因为池中没有足够的可用线程。
Either:
任何一个:
- Use use a larger pool size or use cachedThreadPool
- Change the rejection policy to for example use ThreadPoolExecutor.CallerRunsPolicy
- Create a separate Executor for running the long run tasks and run these from your scheduled task. In actual fact you can do this using the same Executor instance providing that you increase the pool size.
- 使用更大的池大小或使用 cachedThreadPool
- 将拒绝策略更改为例如使用 ThreadPoolExecutor.CallerRunsPolicy
- 创建一个单独的 Executor 来运行长期任务并从您的计划任务中运行这些任务。实际上,您可以使用相同的 Executor 实例来执行此操作,前提是您增加了池大小。
See also ThreadPoolExecutor javadoc
回答by pan40
With Java 7 both of them will wait till the first execution is ready and then start the next!
在 Java 7 中,它们都将等到第一次执行准备就绪,然后开始下一次!
在这里查看:http:
//download.java.net/jdk7/archive/b123/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html
or here:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html
或在这里:http:
//docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

