简体   繁体   English

Future.cancel的用例(false)?

[英]Use case for Future.cancel(false)?

In what situation would one want to pass false for the mayInterruptIfRunning parameter to Future.cancel() ? 在什么情况下,想要将mayInterruptIfRunning参数的false传递给Future.cancel()

If I understand correctly, if you pass false and the task is cancelled but the thread is not interrupted, the result (or ExecutionException ) will never be accessible because the task is still marked as cancelled (ie isCancelled() returns true and get() throws CancellationException .) 如果我理解正确,如果您传递false并且任务被取消但线程没有被中断,则结果(或ExecutionException )将永远不可访问,因为任务仍被标记为已取消(即isCancelled()返回true并且get()抛出CancellationException 。)

Other possible situations are: 其他可能的情况是:

  • The Runnable or Callable implementation does not check for interrupts and will run to completion even if you do interrupt it (here the interrupt makes no difference) RunnableCallable实现不检查中断,即使你中断它也会运行完成(这里中断没有区别)
  • The task already completed before you called cancel() (again the interrupt makes no difference) 在调用cancel()之前,任务已经完成(再次中断没有区别)
  • The task needs to perform some cleanup before it exits (a well-written implementation will use try ... finally for this.) 任务需要在退出之前执行一些清理(一个编写良好的实现将使用try ... finally为此。)
  • The task cannot terminate immediately and must continue to perform operations that would be affected by interrupts, eg blocking I/O (in this case you should probably not call cancel at all) 任务无法立即终止,必须继续执行受中断影响的操作,例如阻塞I / O(在这种情况下,您可能根本不应该cancel

So when/why would you cancel a task without interrupting it? 那么什么时候/为什么你会在不打断任务的情况下取消任务?

tl;dr; TL;博士; Future.cancel(false) is only useful to avoid starting tasks that hadn't already been started. Future.cancel(false)仅用于避免启动尚未启动的任务。

There are two important things to understand regarding concurrency and cancellation. 有关并发和取消的两个重要事项需要了解。

The first is that in Java cancellation is purely cooperative. 首先是在Java中取消纯粹是合作的。 Java signals the cancellation request by having blocking methods throw InterruptedExcetions and by setting a flag on the Thread. Java通过阻塞方法抛出InterruptedExcetions并在Thread上设置一个标志来发出取消请求的信号。 The task implementation is responsible for noticing the cancellation request AND cancelling itself. 任务实现负责注意取消请求并取消自身。 Brian Goetz explains interruption in his post Dealing with InterruptedException . Brian Goetz解释了他在处理InterruptedException的帖子中的中断 Not all task implementations will correctly handle interruption. 并非所有任务实现都能正确处理中断。

The second thing to point out is that the Future object is a placeholder for the results from a task to be executed in the future. 要指出的第二件事是Future对象是一个占位符,用于将来要执行的任务的结果。 If you don't have alot of threads running it is possible that the task starts executing right away but its also possible that all the threads are already being used and the task has to wait. 如果你没有很多线程在运行,那么任务可能会立即开始执行,但也可能是所有线程都已被使用而且任务必须等待。 Just because you have a reference to a Future object that doesn't mean that the corresponding task has actually started running. 仅仅因为您对Future对象的引用并不意味着相应的任务实际上已经开始运行。 Its sort of like a reservation. 这有点像预订。

You have a Future object but the task could be in one of the following states: 您有一个Future对象,但该任务可能处于以下状态之一:

  1. Waiting. 等候。 For example it might be in a queue of other tasks waiting for processor time. 例如,它可能在等待处理器时间的其他任务的队列中。
  2. Running. 运行。
  3. Completed. 已完成。

If your task is in the first state "Waiting" then both Future.cancel(true) and Future.cancel(false) will mark the future as cancelled. 如果您的任务处于第一个状态“Waiting”,那么Future.cancel(true)Future.cancel(false)都会将未来标记为已取消。 The task remains in the queue of tasks to execute but when the executor gets to the task it notices the cancelled flag and skips it. 任务保留在要执行的任务队列中,但是当执行程序到达任务时,它会注意到已取消的标志并跳过它。

If your task is in the third state "Completed" than both Future.cancel(true) and Future.cancel(false) return false and don't do anything. 如果您的任务处于第三个状态“已完成”,则Future.cancel(true)Future.cancel(false)返回false并且不执行任何操作。 Which makes sense because they are already done and there isn't a way to undo them. 这是有道理的,因为它们已经完成,并且没有办法撤消它们。

The mayInterruptIfRunning flag is only important if your task is in the second state "Running". 只有当您的任务处于第二个状态“正在运行”时, mayInterruptIfRunning标志才有用。

If your task is running and mayInterruptIfRunning is false then the executor doesn't do anything and allows the task to complete. 如果您的任务正在运行且mayInterruptIfRunning为false,则执行程序不会执行任何操作并允许任务完成。

If your task is running and mayInterruptIfRunning is true then the executor will interrupt the task. 如果您的任务正在运行并且mayInterruptIfRunning为true,则执行程序将中断该任务。 But remember the bit about cooperative cancellation - for the interruption to work the task has to have been implemented to handle cancellation. 但请记住关于合作取消的一点 - 为了中断工作,必须实施任务来处理取消。

Summary: 摘要:

Future.cancel(true) is appropriate when: Future.cancel(true)适用于:

  1. The Future represents a long running task that is known to have been implemented to handle interruption. Future代表了一个长期运行的任务,已知它已经被实现来处理中断。

Future.cancel(false) would be correct: Future.cancel(false)是正确的:

  1. The task implementation cannot handle being interrupted. 任务实现无法处理被中断。
  2. Its unknown if the task implementation supports cancellation. 如果任务实现支持取消,它是未知的。
  3. You are willing to wait for already started tasks to complete. 您愿意等待已经开始的任务完成。

If you're afraid interrupting the task's execution might leave things in a bad state, and you simply want to mark it as canceled so that users of the Future will be aware of it (eg they should know the statistics requested weren't performed on time). 如果您害怕中断任务的执行可能会使事情处于不良状态,并且您只是想将其标记为已取消,以便Future用户将意识到它(例如,他们应该知道请求的统计信息未执行时间)。

Writing threaded code that handles interrupts correctly is not trivial at all, and so one might simply prefer to avoid it. 编写正确处理中断的线程代码根本不是微不足道的,因此人们可能更愿意避免它。

Some information can be found here , here and of course in the great book Concurrent Programming in Java (by the guy who originally wrote java.util.concurrent ). 有些信息可以发现在这里在这里 ,当然在大书用Java并发编程 (由谁最初写的家伙java.util.concurrent )。

I have a use case that might be interesting to you: I have a single thread that is executing a set of scheduled tasks. 我有一个可能对您感兴趣的用例:我有一个执行一组计划任务的线程。 One of the tasks may be rescheduled by either itself or another task. 其中一项任务可以由其自身或其他任务重新安排。

To do this, I use Future.cancel(false) on the existing copy in the queue, and then schedule the task for the new time. 为此,我在队列中的现有副本上使用Future.cancel(false) ,然后为新时间安排任务。

If this code is called from the scheduled task itself, the cancel operation will be a no-op, and the task will be scheduled to run again in the future. 如果从计划任务本身调用此代码,则取消操作将是无操作,并且该任务将被安排在将来再次运行。 If the code is called from another context, the upcoming task hasn't started execution yet, so it will be canceled, and replaced with a task scheduled for the new time. 如果从另一个上下文调用代码,则即将执行的任务尚未开始执行,因此它将被取消,并替换为为新时间安排的任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM