Java:从代码中调用可中断方法
我正在阅读《Java并发实践》第七章。
在讨论没有自己的取消策略但调用可以中断的方法的部分中,本书有以下内容要说。
不支持取消但仍调用可中断的活动 阻塞方法必须在循环中调用它们,然后重试 检测到中断。在这种情况下,他们应该保存 本地中断状态并在返回前恢复, 而不是立即捕获 InterruptedException。
我还没有完全理解这一点。
这是否意味着,如果我在方法中调用 Thread.sleep ,我将不得不在循环中调用它或其他什么?
谁能解释为什么应该这样做?
I am reading the 7th chapter of Java Concurrency in Practice.
In a section which speaks about methods that do not have a cancellation policy of its own but calls methods that can be interruped, the book has the following thing to say.
Activities that do not support cancellation but still call interruptible
blocking methods will have to call them in a loop, retrying when
interruption is detected.In this case, they should save the
interruption status locally and restore it just before returning,
rather than immediately upon catching InterruptedException.
I haven't understood this fully.
Does it mean, if I call Thread.sleep
in my method, I will have to call it in a loop or something?
Can anyone explain why it should be done so?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当当前线程(被另一个线程)中断时,
Thread.sleep()
将抛出InterruptedException
。如何对此做出反应是你的选择。如果你想睡觉,不管是否有人试图打扰你,那么是的,你必须围绕 try-catch 块构建某种循环。也许您应该使用时钟(例如 System.nanoTime() )来检查在抛出异常之前您睡了多长时间,然后继续睡眠剩余时间等。请注意,InterruptedException仅当另一个线程通过调用
(current)Thread.interrupt()
中断了当前线程时,才会抛出。它不会自行发生,因此通常您不需要围绕睡眠或类似的事情构建任何循环。通常线程只有在有充分理由时才会被中断(例如应用程序关闭),因此您可能希望支持取消/中断,除非没有特殊原因不这样做。例如,“特殊原因”可能是写入 I/O 设备并尝试保证所有数据都将被写入,而不管取消尝试如何。Thread.sleep()
will throw anInterruptedException
when the current thread is interrupted (by another thread). It's your choice how to react to that. If you want to sleep, regardless of if someone is trying to interrupt you, then yes, you have to build some kind of loop around the try-catch block. Probably you should use a clock (e.g.System.nanoTime()
) to check how long you had slept before the exception was thrown, and then continue sleeping for the remaining time etc.Note that
InterruptedException
is thrown only if another thread has interrupted the current thread, by calling(current)Thread.interrupt()
. It doesn't happen by itself, so in general you don't need to build any loops around sleeps or anything like that. Usually threads are interrupted only for a good reason (e.g. application shutting down), so you probably want to support cancellation / interruption unless there's no special reason not to. A "special reason" could be, for instance, writing to an I/O device and trying to guarantee that all data will be written, regardless of cancellation attempts.首先解释一下:
线程的中断状态基本上是一个布尔标志,通过
interrupt()
将其设置为“true”。该标志的当前状态可以使用
Thread.currentThread().isInterrupted()
读取。如果可中断操作(例如
Object.wait()
或Thread.sleep()
)发现已设置中断标志它将抛出一个 InterruptedException,同时清除(设置为“false”)该标志,它可能如下所示:
注意并记住 Thread. Interrupted() 隐式清除中断标志!
这意味着,当执行
catch( InterruptedException ie) {...}
时,线程本身不知道它被中断了。
也就是说,让我们看两个示例:
第一个是支持取消的任务示例。
在这里,我们并不真正关心任务在中止之前进行了多远:
此代码尝试将 x 从 0 计数到 10。如果不被中断,它将完成并输出“x = 10”。
但是,如果线程在中间被中断,则会抛出 InterruptedException,从而中止正在进行的递增 x 的任务。
在这种情况下,输出可能是从“Interrupted: x = 0”到“Interrupted: x = 9”的任何内容,具体取决于线程被中断的时间。
请注意,在退出之前恢复线程的中断标志被认为是很好的做法,因为
否则,此
run()
方法的调用者将看不到中断状态。现在,如果我们的任务完整执行至关重要,以便输出始终为“x = 10”,这意味着该任务不支持取消,我们需要另一种方法:
在这种情况下,即使在 < code>InterruptedException 直到任务完成。
为了保持友好,如果我们检测到中断,我们会将该条件存储在
wasInterrupted
中,以便我们可以从方法返回之前正确设置中断标志。
这就是这个意思
它说“应该”,因为我们并不严格要求以这种方式处理中断 - 我们也可以忽略任何
InterruptedException
完成我们的任务,然后返回。但这不是上面提到的好做法,并且在某些情况下可能会引起麻烦。
Some explanation first:
The interrupted status of a thread is basically a boolean flag, which is set to "true" by
interrupt()
.The current state of this flag can be read using
Thread.currentThread().isInterrupted()
.If an interruptible operation (like
Object.wait()
orThread.sleep()
) finds the interrupted flag setit will throw an
InterruptedException
and at the same time clear (set to "false") the flag, which could look like this:Note and memorize that
Thread.interrupted()
implicitly clears the interrupted flag!This means that, by the time your
catch( InterruptedException ie) {...}
is executed,the thread itself does not know it was interrupted anymore.
That said, let's have a look at two examples:
First an example of a task which supports cancellation.
Here, we don't really care how far the task proceeds before being aborted:
This code tries to count x from 0 to 10. If it is not interrupted, it will complete and output "x = 10".
However, if the thread is interrupted in between, the
InterruptedException
will be thrown, aborting the ongoing task of incrementing x.In this case the output may be anything from "Interrupted: x = 0" to "Interrupted: x = 9", depending on when the thread was interrupted.
Note that it is considered good practice to restore the interrupted flag of the thread before exiting since
otherwise the interrupted status will not be seen by the caller of this
run()
method.Now, if it is crucial that our task executes in full, so that the output will always be "x = 10", which means the task does not support cancellation, we need another approach:
In this case we continue processing even after an
InterruptedException
until the task is completed.To keep being nice, if we detect an interruption, we store that condition in
wasInterrupted
so that we cancorrectly set the interrupted flag before returning from the method.
That's what is meant by
It says "should" because we are not strictly required to handle interruption this way - we may as well just ignore any
InterruptedException
and just complete our task, then return. This is not the good practice mentioned above, though, and may cause trouble in some scenarios.
据我了解:一个长时间运行的服务,其本身不能或不应该被中断,正在调用其他可以被中断的方法。因此,这个长时间运行的服务应该能够检测到这一点并通过方法或标志报告它。但它应该能够再次尝试该操作,而不是仅仅抛出 InterruptedException。
调用阻塞方法意味着当前执行被阻塞并等待,直到阻塞方法返回一个值。这可以循环完成。然后您就知道方法调用是否成功或者调用的方法是否被中断。
As far as I understand this: A long running Service, that cannot itself be or should not be interrupted, is calling other methods that can be interrupted. So this long running Service should be able to detect this and report it through a method or a flag. But it should be able to try the operation again instead of just throw the InterruptedException.
To call a method that blocks means, the current execution is blocked and is waiting until the blocking method will return a value. This could be done in a loop. You know then if the method call was successfull or if the method called is interrupted.
我没有这本书。但据我了解,如果一个活动中断(顺便说一下,睡眠不是一个中断信号。但是您可以通过中断信号将线程从睡眠状态唤醒),该活动需要保存其当前的动态数据(中断状态)以便恢复自身并从之前的状态恢复。例如;
希望这会有所帮助,我仍然很困,可能有错误:)
I don't have the book. But as far as i understood, if an activity interrupted (sleep is not an interrupt signal by the way. But you can awaken a thread from sleep via interrupt signal), the activity needs to save it's current dynamic data(interruption status) in order to restore itself and resume from previous state. For example;
Hope this helps, i am still sleepy there might be an error :)