我知道正常终止线程的构造:
public class Foo implements Runnable {
private volatile boolean stop = false;
public void stop() {
stop = true;
}
public void run() {
while (!stop) {
...
}
}
}
但是如果某个线程正在等待某个东西,在某个对象内(使用wait()
,没有时间限制),那么这个构造对于停止这个线程没有用,因为他已经超过了while循环,所以他会永远继续。
那么,停止等待线程的正确方法是什么?
答案 0 :(得分:2)
如果您不希望线程无限期地等待,请不要将它们编码为首先执行此操作。你正在编写他们的代码,所以写它来做你真正的事情所以你不必尝试从外面修复它。
答案 1 :(得分:2)
如果线程实际等待某事,你应该调用方法Thread.interrupt()来中断线程。不要在while循环中检查自定义变量,而是使用Thread.isInterrupted()或Thread.interrupted() - 一个重置中断标志,另一个不重置。
如果你在等待什么,我认为你必须抓住InterruptedException,不是吗?
答案 2 :(得分:1)
每个行为良好的阻塞方法都会声明一个已检查的异常InterruptedException
,它实现了这个目的:通知线程在被阻塞时被中断。
您必须捕获此异常,实际上这可能会替换您的stop
字段。
例如,让我们考虑一个日志系统,它将消息写入专用线程上的文件(这样在IO上花费的时间不会干扰您的应用程序 - 假设它不是IO重)。
每个线程都有一个 initerrupted flag ,可以通过Thread.currentThread().isInterrupted()
读取。你尝试这样的事情:
class Logger {
private final File file = ...;
private final BlockingQueue<String> logLines = new LinkedBlockingQueue<String>();
private final Thread loggingThread = new Thread(new Runnable(){
@Override public void run() {
PrintWriter pw;
try {
pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
while (!Thread.currentThread().isInterrupted()) {
try {
pw.println(logLines.take());
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // good habit: make sure the interrupt status is set
}
}
pw.flush();
pw.close();
} catch (IOException e) { ... flush and close pw if not null and open ... }
}
});
{ loggingThread.start(); }
public void log(final String line) { logLines.offer(line); } // will always work, because logLines is a LinkedBQ.
public void stop() { loggingThread.interrupt(); }
}
最后,为了正常关闭应用程序,必须确保在让JVM关闭之前终止此线程。要做到这一点,你必须绝对肯定在以任何可能的方式关闭之前调用stop()
,或者你可以注册一个关闭钩子,通过在类中添加类似这个实例初始化器的东西:
class Logger {
...
{
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override public void run() { close(); }
}));
}
}
这将强制JVM在终止之前调用close()(因此中断线程,刷新并关闭文件)。
答案 3 :(得分:0)
这一切都取决于你必须在你的线程中等待的原因。如果线程正在等待不间断IO,那么您可以查看Stop/Interrupt threads blocked on waiting input from socket
否则全部取决于你在线程中的等待方式。您可以使用wait(1000)
,然后检查标志并等待一些。您可以等待来自阻塞队列的消息,您可以使用锁/条件,即使wait/notify
可以在这种情况下工作,您也需要正确处理中断。