每个行为良好的阻塞方法都声明了一个已检查异常InterruptedException
,这正是服务于这个目的:通知线程在被阻塞时已被中断。
您必须捕获此异常,实际上这可能会替换您的stop
字段。
例如,让我们考虑一个日志系统,它将消息写入专用线程上的文件(这样在 IO 上花费的时间不会干扰您的应用程序——假设它不是 IO 繁重的)。
每个线程都有一个可以读取的中断标志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() (因此中断线程、刷新和关闭文件)。