免责声明:这个答案具有教程性质。
基本方法:我们最初让事情变得简单,并且不处理期间的中断Thread.sleep
方法。本质上,您应该有一个外部可设置的变量,run 方法在循环的每次迭代时都会检查该变量;然后你可以设置该变量来优雅地终止run()
方法。请注意这个习惯用法如何可以轻松地用于 Java 以外的语言。
例如:
public class MyThreadedClass extends Thread {
private volatile boolean completed = false;
public void setCompleted() {
this.completed = true;
}
public void run()
{
while (!completed) {
// do anything you fashion
}
}
public static void main(String... args)
{
MyThreadedClass x = new MyThreadedClass();
MyThreadedClass y = new MyThreadedClass();
x.start();
y.start();
x.setCompleted(); // will complete as soon as the latest iteration finishes
...
}
}
COMMENTS:易失性标志告诉编译器completed
可能(并且将会)在控制范围之外进行更改run()
函数,即另一个线程可能会改变它。否则,循环中的迭代检查可能会根据类的唯一同步行为被错误地优化。
在你的具体run()
情况下,我们利用for
循环,所以我们的方法转化为以下内容:
public void run()
{
try {
for(int i=0;i<20 && !completed;++i) {
Thread.sleep(500);
System.out.print(i +"\n"+ "..");
}
} catch(Exception e) {
e.printStackTrace();
}
}
COMMENTS:很明显,由于 sleep 调用,您可能需要等待 500 毫秒。但是,如果您的代码通常必须执行改变变量状态的操作(特别是,如果这些变量在多个线程之间共享!),那么您就不会让这些变量处于不正确的状态。在实践中,你可以正确处理交易因为您可以控制终止。这显然假设在循环的每次迭代结束时,变量状态是一致的。
现在让我们改进处理期间中断的基本方法Thread.sleep
.
完整答案:这个答案涉及到,从调用方来说,使用Thread.interrupt()
方法,这使得该方法严格特定于 Java。
public class MyThreadedClass extends Thread {
public void run()
{
try {
for(int i=0;i<20 && !this.isInterrupted();++i) {
Thread.sleep(500);
System.out.print(i +"\n"+ "..");
...
// some molassy slow code here, where you may sprinkle isInterrupted()
// checks and consequent break statements
}
} catch(InterruptedException e) {
// do whatever you need to clean things up
} catch(Exception e) {
// handle other exceptions as seen fit
}
}
public static void main(String... args)
{
MyThreadedClass x = new MyThreadedClass();
x.start();
// will complete
// a) as soon as one isInterrupted() check breaks the loop, or
// b) "immediately" during the blocking call to sleep()
x.interrupt();
...
}
}
COMMENTS:在这种情况下,线程本身已经完成了一半的工作。如果您只需要在执行期间中断Thread.sleep
调用,那么你除了处理之外不需要做任何事情InterruptedException
如有必要,清理您的状态。相反,如果您需要在“慢速”代码期间中断,则必须调用this.isInterrupted()
无论您喜欢什么地方(可能在多个地方)并打破循环;循环条件内的调用很常见,但不是必需的。
更多信息可以在 Java 并发中找到中断教程 http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html.