我更改了文本,因此某些注释可能引用了以前的版本
下面是代码示例。有两个线程:观察者和可观察者。可观察是由主开始的。观察者从可观察对象的创建开始,并以其破坏结束。但这不会发生,并且观察者将永远运行。为什么?
public class ThreadObjectReaping01 {
private static final Logger log = LoggerFactory.getLogger(ThreadObjectReaping01.class);
public static void main(String[] args) throws InterruptedException {
Thread observable = new Thread("observable") {
private Thread observable2 = this;
Thread observer = new Thread("observer") {
@Override
public void run() {
log.info("Observer is starting");
while(!interrupted()) {
if( observable2.isAlive() ) {
log.info("Observable is running");
}
else {
log.info("Observable is NOT running");
}
try {
sleep(1000);
} catch (InterruptedException e) {
interrupt();
}
}
log.info("Observer is terminating");
}
};
{
observer.start();
}
@Override
protected void finalize() throws Throwable {
observer.interrupt();
}
@Override
public void run() {
log.info("Observable is starting");
while(!interrupted()) {
try {
sleep(1000);
} catch (InterruptedException e) {
interrupt();
}
//log.info("Observable is running");
}
}
};
log.info("Main is starting observable");
observable.start();
Thread.sleep(10000);
log.info("Main is interrupting observable");
observable.interrupt();
observable = null;
Thread.sleep(10000);
log.info("Main is terminating");
}
}
最佳答案
当您的主要对象(重写finalize()
)不再可用(有资格进行垃圾回收)时,GC将首先调用finalize()
。我看到您正在跟踪它,因此请确保实际上已调用您的日志记录消息。
但是,仅仅调用interrupt()
是不够的,守护程序线程必须主动检查该标志(使用isInterrupted()
)并正确响应它,并尽快关闭。另外,您应该正确处理InterruptedException
(如果有)。
您的线程是守护程序线程这一事实是无关紧要的。非守护程序线程阻止JVM退出(当所有非守护程序线程完成其工作时,JVM就会存在)。在这里,您正在手动中断线程-该线程是否是守护程序都没有关系。
您的"Reporting of..."
消息曾经显示吗?您可以在此处放置一个断点。这意味着实现finalize()
的对象是GC的受害者。如果只有reporter
线程持有对您的主对象的引用(反之亦然),即使没有循环引用,如果外部都未引用这些对象,GC仍将释放这些对象。
也可以看看:
圣经后
与您的问题无关。如果您使用的是slf4j,则:
log.info(String.format("Reporting of (%s) is about ot interrupt", getName()));
可以替换为:
log.info("Reporting of {} is about to interrupt", getName());
关于java - 如何配置一对相关的线程对象?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11674664/