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块中