2011-04-06 113 views
6

我正在使用ThreadPoolExecutor在我的Java应用程序中执行任务。我有一个要求,我希望在执行程序队列中的任意时间点获取队列中活动任务的数量。我抬头看看ThreadPoolExecutor的javadoc,发现了两个相关的方法:getTaskCount()getCompletedTaskCount()使用ThreadPoolExecutor的活动任务数

根据文档,我可以分别从上述两种方法中获取计划任务的数量和完成的任务。但是我无法找到解决方案,以便在任何时间点获取队列中活动任务的数量。我可以这样做:

getTaskCount() = getCompletedTaskCount() + failed tasks + active tasks 

但是失败的任务数量不能直接用于达到预期的计算。

我在这里错过了什么吗?

+5

你的说法(“队列中的活动任务”)自相矛盾:你想“活动任务”或“队列中的任务”?由于队列中的任务未处于活动状态,因此它们将排队。 – 2011-04-06 21:12:26

+0

另外,你能澄清你的意思是“失败的任务”吗?什么构成失败完全取决于你; ThreadPoolExecutor实际上只有一个线程完成的概念,或者在执行期间发生了一些(非业务逻辑)系统错误。如果您需要检查返回状态或捕获检查异常以确定失败,则需要使用['Future'](http://download.oracle.com/javase/6/docs/api/java/util/concurrent /Future.html)s。 – 2011-04-06 21:41:08

+0

我对不准确的要求表示歉意。我基本上是在运行时试图找出已安排但尚未完成的任务数量。而且我会将“失败的任务”视为已安排的任务,但由于某些错误未成功完成。 – invinc4u 2011-04-07 19:15:54

回答

19

我不认为你需要知道失败的计数与你试图使用的计算。

long submitted = executor.getTaskCount(); 
long completed = executor.getCompletedTaskCount(); 
long notCompleted = submitted - completed; // approximate 

会(近似)足够。


或者,你可以使用getQueue()size()

int queued = executor.getQueue().size(); 
int active = executor.getActiveCount(); 
int notCompleted = queued + active; // approximate 

这个答案假定你正在寻找一个 “尚未完成” 计数。你的问题自相矛盾,所以我不完全确定你在问什么。回复我对你的问题的评论,如果这是不正确的,我会相应地更新这个答案。

+0

第二种解决方案是我正在寻找的解决方案,它适用于我。谢谢你的帮助。 – invinc4u 2011-04-07 19:17:09

+0

请记住,某些Queue实现不支持size()方法的O(1)操作,并且这可能需要比预期更长的时间。 – user482594 2017-12-01 18:29:24

4

您是否尝试过使用beforeExecute和afterExecute方法?这些在执行任务之前和之后调用。 after执行方法甚至提供了一个throwable作为第二个参数,所以你知道任务何时失败。

您可以添加一个钩子,以便beforeExecute递增活动任务的值,afterExecute递减它。当然,这些方法在它们各自的字段上被调用,所以你必须在一个相互锁定的对象上同步结果。

要使用这些方法,只需重写您选择的ThreadPoolExecutor对象并在其中添加钩子。

例如,下面的代码应该有希望的工作:

public class MyExecutor extends ThreadPoolExecutor { 
     //Lock object used for synchronization 
     private final Object lockObject = new Object(); 
     //Contains the active task count 
     private int activeTaskCount = 0; 
     //Failed task count 
     private int failedTaskCount = 0; 
     private int succeededTaskCount = 0; 

     public MyExecutor() { 
      //call super here with your parameters; 
     } 

     public int getActiveTaskCount(){ 
      synchronized(lockObject){ 
       return activeTaskCount; 
      } 
     } 

     public int getFailedTaskCount(){ 
      synchronized(lockObject){ 
       return failedTaskCount ; 
      } 
     } 

     public int getSucceededTaskCount(){ 
      synchronized(lockObject){ 
       return succeededTaskCount ; 
      } 
     } 

     protected void beforeExecute(Thread t, 
          Runnable r){ 
      super.beforeExecute(t,r); 
      synchronized(lockObject){ 
       activeTaskCount++; 
      } 
     } 

     protected void afterExecute(Runnable r,Throwable t){ 
      super.afterExecute(r,t); 
      synchronized(lockObject){ 
       activeTaskCount--; 
       if(t!=null){ 
        failedTaskCount++; 
       }else{ 
        succeededTaskCount++; 
       } 
      } 
     } 

} 
+1

这似乎没有必要; ThreadPoolExecutor已经提供了[getActiveCount()](http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html#getActiveCount())。 – 2011-04-06 21:28:26

+0

是的,但不是失败的计数,这种方法可以提供。检查afterExecute方法中的注释。你甚至可以检查哪些runnables正在运行,如果你把它们全部放在一个集合中。这个方法允许比我在我的简单示例中发布更多的可能性。 – Tovi7 2011-04-06 21:31:33

+0

我的确在那里错过了你的评论;它可能更好地为了举例而用实例展示失败的计数而不是活动计数。此外,'t == null'检查只会检查从执行中(而不是业务逻辑“失败)抛出的*严重*错误(未检查,即'RuntimeException','Error's)。 “失败”和“成功”的概念完全取决于使用API​​的开发人员(应该使用Future来完成,而不是从正在执行的线程抛出RuntimeException)。 – 2011-04-06 21:42:35

相关问题