Java执行官:如何停止提交的任务?

我已经使用执行程序提交了一个任务,我需要它在一段时间后停止(例如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 } } 

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

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

有什么不对? 如何停止提交的5分钟后仍在工作的任务?

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

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

例如:

 class LongTask implements Callable { 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; } } 

另外,正如其他post所提到的:即使使用线程安全的Vector类也可以抛出ConcurrentModificationException ,因为从Vector获取的迭代器不是线程安全的,因此需要进行同步。 高级for循环使用迭代器,因此请注意:

 final Vector vector = new Vector(); 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); } } 

ConcurrentModificationException来自您对tasks.clear()调用,而您的Exceutors正在迭代您的tasks Vector 。 您可以尝试做的是在ExecutorService上调用shutdownNow()

ConcurrentModificationException的最常见情况是在迭代时同时修改vector 。 通常这将在一个线程中完成。 你需要在整个迭代中对Vector进行锁定(并注意不要死锁)。

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

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

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

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

放下fut.cancel(true); 在finally块中