17

我已经使用 executors 提交了一个任务,我需要它在一段时间后停止(例如 5 分钟)。我试过这样做:

   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 分钟后仍在工作的任务?

4

5 回答 5

29

仅仅因为你调用并不意味着任务会自动停止cancel()Future您必须在任务中做一些工作以确保它会停止:

  • 使用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);
    }
}
于 2009-09-13T16:57:13.753 回答
1

当您的ConcurrentModificationExceptionExecutorstasks.clear()迭代您的tasks Vector. 你可以尝试做的是调用shutdownNow()你的 ExecutorService

于 2009-09-13T16:15:56.477 回答
0

最常见的情况ConcurrentModificationExceptionvector在迭代的同时修改。通常这将在一个线程中完成。您需要Vector在整个迭代中保持锁定(并注意不要死锁)。

于 2009-09-13T15:57:27.530 回答
0

fut.get() 是一个阻塞调用,即使在超时之后,你也会阻塞直到任务完成。如果您想在 5 分钟标记处尽可能停止,您确实需要检查中断标志,我只是建议您使用保留中断状态的 Thread.isInterrupted() 方法这样做。如果您只想立即停止并且不需要清除任何状态,则抛出一个异常,该异常将被 Future 捕获并指示为 ExecutionException。

fut.cancel(true) 没有做任何事情,因为 invokeAll() 方法已经为您完成了这项工作。

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

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

于 2009-09-14T18:42:49.873 回答
-1

放入fut.cancel(true); finally块

于 2012-10-17T03:55:47.770 回答