8

我有这个问题,我有

private ScheduledExecutorService executor =  
     Executors.newSingleThreadScheduledExecutor(); 

以及每 50 毫秒创建一次的任务:

executor.scheduleAtFixedRate(myTask, 0, 50, TimeUnit.MILLISECONDS);

myTask有时需要一段时间才能完成(比如 2-3 秒左右),但 newSingleThreadScheduledExecutor 保证下一个计划的 myTask 将等到当前的完成。

但是,我不时收到此错误:

执行:java.util.concurrent.RejectedExecutionException

我该怎么办?谢谢

4

3 回答 3

15

考虑执行者在做什么。根据您的指示,它每 50 毫秒运行一个任务。假设这个任务的运行时间少于 50 毫秒,那么一切都很好。但是,每隔一段时间就需要 2-3 秒才能运行。发生这种情况时,执行器仍会尝试每 50 毫秒执行一次,但因为它只有一个线程,所以它不能,并拒绝那些在您的长时间运行的任务仍在进行时被触发的执行。这会导致您看到的异常。

您有两种选择来解决此问题(假设您想坚持使用单个线程):

  1. 使用scheduleWithFixedDelay而不是scheduleAtFixedRate. 如果您仔细阅读 javadoc,您会发现scheduleWithFixedDelay在完成一项任务和开始下一项任务之间将等待 50 毫秒,因此它永远不会“重叠”,即使其中一项需要很长时间。相反,scheduleAtFixedRate将尝试每 50 毫秒执行一次,而不管每个执行需要多长时间。

  2. 更改执行器处理执行失败的方式。默认是记录一个异常,但你可以告诉它忽略它,例如。看一下 of 的子类java.util.concurrent.RejectedExecutionHandler,例如DiscardPolicy,它只是默默地丢弃了无法运行的任务。您可以通过直接构造ScheduledThreadPoolExecutor处理程序并将其传递给构造函数来使用它们,而不是使用Executors工厂类。

我怀疑选项(1)是你想要的。

于 2009-12-21T08:31:42.330 回答
4

在以下任一情况下将引发此异常:

  1. 您已关闭 Executor
  2. 已超出 Executor 的工作队列界限或最大线程数。

我认为后者正在发生。当您执行任务并且需要很长时间时,随后的计划任务将无法运行,因为池中没有足够的可用线程。

任何一个:

  1. 使用更大的池大小或使用 cachedThreadPool
  2. 将拒绝策略更改为例如使用 ThreadPoolExecutor.CallerRunsPolicy
  3. 创建一个单独的 Executor 来运行长期任务并从您的计划任务中运行这些任务。实际上,只要您增加池大小,您就可以使用相同的 Executor 实例来执行此操作。

另请参见ThreadPoolExecutor javadoc

于 2009-12-21T04:19:39.347 回答
-1

在 Java 7 中,它们都将等待第一次执行准备好,然后开始下一次执行!

在这里检查:http:
//download.java.net/jdk7/archive/b123/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

或在这里:
http ://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

于 2014-06-05T11:09:43.903 回答