2009-09-13 74 views
9

我已经使用执行程序提交了一个任务,并且需要它在一段时间后停止(例如5分钟)。我试图做这样的:Java执行者:如何停止提交的任务?

for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) { 
     try { 
      fut.get(); 
     } catch (CancellationException ex) { 
      fut.cancel(true); 
      tasks.clear(); 
     } catch(ExecutionException ex){ 
      ex.printStackTrace(); //FIXME: gestita con printstack  
     } 
    } 

但我总是得到一个错误:我有一个共同的载体,需要由任务由一个线程修改,然后阅读,即使我停止所有的任务,如果发生超时,我得到:

Exception in thread "Thread-1" java.util.ConcurrentModificationException 

有什么错吗?如何停止5分钟后仍在工作的任务?

+0

@Raffaele迪法齐奥:我已格式化的代码 - 并增加了一个右括号,请检查的准确性。 – akf 2009-09-13 16:18:16

+0

谢谢,我很抱歉格式不正确。 – Raffo 2009-09-13 17:02:45

回答

20

仅因为您在Future上拨打cancel()并不意味着该任务将自动停止。你必须在任务中做一些工作,以确保它能够停止:

  • 使用cancel(true),以便中断发送到任务。
  • 手柄InterruptedException。如果任务中的函数引发InterruptedException,请确保在捕获异常时尽快正常退出。
  • 定期检查Thread.currentThread().isInterrupted()如果任务执行连续计算。

例如:

class LongTask implements Callable<Double> { 
    public Double call() { 

     // Sleep for a while; handle InterruptedException appropriately 
     try { 
      Thread.sleep(10000); 
     } catch (InterruptedException ex) { 
      System.out.println("Exiting gracefully!"); 
      return null; 
     } 


     // Compute for a while; check Thread.isInterrupted() periodically 
     double sum = 0.0; 
     for (long i = 0; i < 10000000; i++) { 
      sum += 10.0 
      if (Thread.currentThread().isInterrupted()) { 
       System.out.println("Exiting gracefully"); 
       return null; 
      } 
     } 

     return sum; 
    } 
} 

而且,其他职位都提到:ConcurrentModificationException可即使使用线程安全Vector类抛出,因为迭代器从Vector获得不是线程安全的,因此需要同步。先进的for循环使用迭代器,所以注意:

final Vector<Double> vector = new Vector<Double>(); 
vector.add(1.0); 
vector.add(2.0); 

// Not thread safe! If another thread modifies "vector" during the loop, then 
// a ConcurrentModificationException will be thrown. 
for (Double num : vector) { 
    System.out.println(num); 
} 

// You can try this as a quick fix, but it might not be what you want: 
synchronized (vector) { // "vector" must be final 
    for (Double num : vector) { 
     System.out.println(num); 
    } 
} 
+0

优秀 - 不知何故,我从来没有遇到过线程。中断() - 明天我可以使用它! – 2009-09-14 05:22:36

+7

首先,调用future.cancel(true)完全没有任何作用。 invokeAll的合约声明它将在返回之前取消任务,并且实现使用最后的块来确保它。其次,不要调用Thread.interrupted(),这样做会清除线程的中断状态。大多数实现都想使用Thread.isInterrupted()。应该仔细检查清除旗帜。第三,他不必处理InterruptedException,除非他使用锁定方法,例如锁定获取,然后编译器确保他是。 FutureTask将会捕获异常。 – 2009-09-14 06:41:44

+1

@Tim Bender:你说得对:future.cancel(true)什么都不做,由我自己测试。但我还没有明白你认为我应该怎么做。 – Raffo 2009-09-14 08:50:28

0

ConcurrentModificationException最常见的情况是当vector在被迭代的同时被修改。通常这将在单个线程中完成。您需要在整个迭代过程中锁定Vector(并注意不要死锁)。

+0

是的,我知道为什么异常被抛出,但它不应该。迭代是在我发布的代码部分之后,因此,如果代码运行良好,我不应该得到一个异常... – Raffo 2009-09-13 16:14:22

1

ConcurrentModificationException从您的来电tasks.clear(),而你的Exceutors被遍历您tasksVector到来。您可以尝试在您的ExecutorService上拨打shutdownNow()

+0

这似乎不工作... – Raffo 2009-09-13 17:41:33

0

fut.get()是一个阻塞调用,即使超时后,你会被阻塞,直到任务完成。如果你想尽可能接近5分钟,你需要检查中断标志,我建议你使用保留中断状态的Thread.isInterrupted()方法。如果你想立即停止并且不需要清理任何状态,那么抛出一个异常,这个异常将被未来捕获并且以ExecutionException的形式表示给你。

fut.cancel(true)不会执行任何操作,因为invokeAll()方法已经为您执行了此操作。

除非您在其他地方使用“任务”集合,否则您可能不需要对其调用clear()。这不会是你的问题的根源,因为在你调用clear()的时候invokeAll()方法是通过List完成的。但是,如果您需要开始形成要执行的新任务列表,我建议您形成新的任务列表,而不是使用旧任务列表中的新任务。

不幸的是,我没有你的问题的答案。我没有看到足够的信息来诊断它。您提供的代码片段中没有任何内容表示对类库/方法的使用不恰当(只是不必要的)。也许如果你包含完整的堆栈跟踪,而不是一行错误。

+0

我在其他地方使用了集合,并且它在while循环中,所以需要清除以便在循环重复时为空。当然,我可以在帖子中显示的代码之后执行clear(),这应该没问题。 我的问题的重要部分不是例外:我需要知道的是如何在5分钟后停止未来,当然,我会尝试按照您的建议抛出异常。我甚至可以改变我提交任务的方式。我在这里学到了这种方式:http://stackoverflow.com/questions/1322147/help-with-java-executors-wait-for-task-termination – Raffo 2009-09-14 19:27:23

-1

fut.cancel(true);在finally块

+0

你的意思是在一个被添加的'finally'块,对吧? – 2015-10-21 08:37:09