Java Executors:如何停止提交的任务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1418033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Executors: how can I stop submitted tasks?
提问by Raffo
I have submitted a task using executors and I need it to stop after some time (e.g. 5 minutes). I have tried doing like this:
我已经使用 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
}
}
But I always get an error: I have a shared Vector that needs to be modified by the tasks and then read by a thread, and even if I stop all the task, if the timeout occurs I get:
但是我总是得到一个错误:我有一个共享的 Vector 需要由任务修改然后由线程读取,即使我停止所有任务,如果发生超时,我会得到:
Exception in thread "Thread-1" java.util.ConcurrentModificationException
Is there something wrong? How can I stop the tasks submitted that are still working after 5 minutes?
有什么不对?如何停止提交的任务在 5 分钟后仍在工作?
采纳答案by Matt Fichman
Just because you call cancel()
on Future
doesn't mean that the task will stop automatically. You have to do some work within the task to make sure that it will stop:
仅仅因为你叫cancel()
上Future
并不意味着任务将自动停止。您必须在任务中做一些工作以确保它会停止:
- Use
cancel(true)
so that an interrupt is sent to the task. - Handle
InterruptedException
. If a function in your task throws anInterruptedException
, make sure you exit gracefully as soon as possible upon catching the exception. - Periodically check
Thread.currentThread().isInterrupted()
if the task does continuous computation.
- 使用
cancel(true)
以便向任务发送中断。 - 处理
InterruptedException
。如果任务中的函数抛出InterruptedException
,请确保在捕获异常后尽快正常退出。 - 定期检查
Thread.currentThread().isInterrupted()
任务是否进行连续计算。
For example:
例如:
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;
}
}
Also, as other posts have mentioned: ConcurrentModificationException
can be thrown even if using the thread-safe Vector
class, because iterators you obtain from Vector
are not thread-safe, and thus need to be synchronized. The advanced for-loop uses iterators, so watch out:
此外,正如其他帖子所提到的: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);
}
}
回答by Tom Hawtin - tackline
The most common case for ConcurrentModificationException
is when the vector
is being modified at the same time as it is being iterated. Often this will be done in a single thread. You need to hold a lock on the Vector
for the whole iteration (and careful not to deadlock).
对于最常见的情况ConcurrentModificationException
中,当是vector
在同一时间被修改,因为它是被重复。通常这将在单个线程中完成。您需要Vector
在整个迭代过程中保持锁定(并注意不要死锁)。
回答by akf
The ConcurrentModificationException
is coming from your call to tasks.clear()
while your Exceutors is iterating over your tasks
Vector
. What you can try to do is call shutdownNow()
on your ExecutorService
该ConcurrentModificationException
从你的电话来tasks.clear()
,而你的Exceutors是迭代的tasks
Vector
。您可以尝试做的是调用shutdownNow()
您的 ExecutorService
回答by Tim Bender
fut.get() is a blocking call, even after the timeout, you will block until the task is done. If you want to stop as close to the 5 minute mark as possible, you do need to check the interrupt flag, I just recommend you do so using the Thread.isInterrupted() method which preserves the interrupt state. If you want to just stop immediately and don't need to clean any state, then throw an exception which will be caught by the Future and indicated to you as an ExecutionException.
fut.get() 是一个阻塞调用,即使在超时之后,你也会阻塞直到任务完成。如果你想在尽可能接近 5 分钟时停止,你需要检查中断标志,我只是建议你使用 Thread.isInterrupted() 方法来保持中断状态。如果您只想立即停止并且不需要清除任何状态,则抛出一个异常,该异常将被 Future 捕获并指示为 ExecutionException。
fut.cancel(true) does not do anything as the invokeAll() method has already done this for you.
fut.cancel(true) 不会做任何事情,因为 invokeAll() 方法已经为您完成了这项工作。
Unless you use the "tasks" Collection somewhere else, you probably don't need to call clear() on it. This isn't going to be the source of your problem since the invokeAll() method is done with the List by the time you call clear(). But, if you need to start forming a list of new tasks to execute, I suggest you form a new List of tasks, not use an old List of new Tasks.
除非您在其他地方使用“任务”集合,否则您可能不需要对其调用 clear() 。这不会是您的问题的根源,因为在您调用 clear() 时 invokeAll() 方法已与 List 一起完成。但是,如果您需要开始形成要执行的新任务列表,我建议您形成一个新的任务列表,而不是使用旧的新任务列表。
Unfortunately, I do not have an answer for your problem. I do not see enough information here to diagnose it. Nothing in the code snippet you provided indicates an improper (only unnecessary) use of library classes/methods. Perhaps if you included a full stack trace, instead of the one line error.
不幸的是,我没有你的问题的答案。我在这里没有看到足够的信息来诊断它。您提供的代码片段中没有任何内容表明库类/方法的使用不当(只是不必要的)。也许如果您包含完整的堆栈跟踪,而不是一行错误。
回答by clinton
Put the fut.cancel(true);
in the finally block
将 放在fut.cancel(true);
finally 块中