Java 当有等待线程时,如何优雅地降级程序?
我知道如何优雅地终止线程:Java 当有等待线程时,如何优雅地降级程序?,java,multithreading,concurrency,graceful-degradation,Java,Multithreading,Concurrency,Graceful Degradation,我知道如何优雅地终止线程: public class Foo implements Runnable { private volatile boolean stop = false; public void stop() { stop = true; } public void run() { while (!stop) { ... } } } 但是如果某个线程正在某个对象内等待某个东西(使用wait(),
public class Foo implements Runnable {
private volatile boolean stop = false;
public void stop() {
stop = true;
}
public void run() {
while (!stop) {
...
}
}
}
但是如果某个线程正在某个对象内等待某个东西(使用wait()
,没有时间限制),那么此构造对于停止此线程将没有用处,因为他已经超过while循环中的条件,因此他将永远继续
那么,停止等待的线程的正确方法是什么呢?如果您不希望线程无限期地等待,那么首先不要编写代码让它们这样做。您正在编写他们的代码,所以编写代码时要按照实际操作,这样您就不必尝试从外部修复代码。这取决于您为什么要在线程中等待。如果线程正在等待不间断IO,那么您可以查看 否则,这完全取决于线程中的等待方式。您可以使用
wait(1000)
,然后检查标志并再等待一段时间。您可以等待来自阻塞队列的消息,可以使用锁/条件,甚至wait/notify
都可以工作。在这种情况下,您需要正确处理中断。如果线程确实在等待某个消息,您应该调用该方法来中断线程。使用Thread.isInterrupted()或Thread.interrupted()-一个重置中断标志,另一个不重置,而不是在while循环中检查自定义变量
如果您正在等待某些内容,我认为您必须捕获,不是吗?每个行为良好的阻塞方法都会声明一个checked exception
InterruptedException
,它的确切用途是:通知线程在阻塞时已被中断
您必须捕获此异常,实际上这可以替换stop
字段
例如,让我们考虑一个日志系统,它将消息写入一个专用线程上的一个文件(这样,在IO上花费的时间不会干扰您的应用程序——假设它不是IO重)。 每个线程都有一个initerrupted标志,可以通过
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在终止之前调用close()(因此中断线程,刷新并关闭文件)。您的构造不正确,
stop
变量必须是volatile
@Leif Ericson:实际上,如果您的程序是多线程的,您可能正在调用stop())方法:因此,您希望将private boolean stop=false更改为private volatile boolean stop=false,因为否则,无法保证run()方法在您从另一个线程更改后读取正确的停止值。@denis您的第一条语句是正确的(OP的构造不正确)。您的第二个语句不正确,因为您还可以使用方法调用。@denis我的意思是,如果您在(!shouldStop())时使用了,则不需要将其设置为易失性的。您的声明说它必须是volatile,虽然它是最简单的解决方案,但不是唯一的解决方案。只有西斯是绝对的(绝地武士对西斯的观察除外)。@glowcoder如果你在(!shouldStop())
时做了shouldStop()
你需要将shouldStop()和stop()
标记为同步的。在这种情况下,是的,你是对的:)我别无选择。线程必须在我的程序中等待。我可以使用wait(X)
,但我不能只是抛出一个随机数。如果你想让线程无限期地等待,请编写代码让它们这样做。但不要让他们无限期地等待,然后抱怨他们无限期地等待。仔细考虑一下您希望线程做什么,然后编写代码让它们这样做。这样,你就不必想办法“让他们”做你想做的事。
class Logger {
...
{
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override public void run() { close(); }
}));
}
}