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

有帮助吗?

解决方案

只因为你打电话 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);
    }
}

其他提示

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

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

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

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

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

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

fut.cancel(true); 放入finally块

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top