Java 如何处理一对相关的线程对象?
我已经更改了文本,因此一些评论可能会引用以前的版本 下面是代码示例。有两条线索:观察者和可观察者。可观察的由main启动。观察者从可观察对象的创建开始,并打算以其破坏结束。但这不会发生,观察家永远在运行。为什么?Java 如何处理一对相关的线程对象?,java,multithreading,garbage-collection,slf4j,Java,Multithreading,Garbage Collection,Slf4j,我已经更改了文本,因此一些评论可能会引用以前的版本 下面是代码示例。有两条线索:观察者和可观察者。可观察的由main启动。观察者从可观察对象的创建开始,并打算以其破坏结束。但这不会发生,观察家永远在运行。为什么? public class ThreadObjectReaping01 { private static final Logger log = LoggerFactory.getLogger(ThreadObjectReaping01.class); public static vo
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()
)并正确响应,尽快关闭。此外,您还应正确处理中断异常(如果有)
您的线程是守护进程线程这一事实与此无关。非守护进程线程阻止JVM退出(当所有非守护进程线程完成其工作时JVM存在)。在这里,您手动中断线程-不管该线程是否为守护进程
这仅仅是一个垃圾收集器延迟,还是线程永远不会结束,因为主对象没有被删除,因为它被reporter引用
您的“报告…”
消息是否显示过?您可以在那里设置断点。这意味着实现finalize()
的对象是GC的受害者。如果只有reporter
thread持有对主对象的引用(反之亦然),尽管存在循环依赖关系,但如果没有外部引用这些对象,GC仍将释放这些对象
另见:
log.info("Reporting of {} is about to interrupt", getName());
当您的主对象(覆盖
finalize()
)不再可访问(符合垃圾收集的条件)时,GC将首先调用finalize()
。我看到您正在跟踪它,所以请确保您的日志消息实际上已被调用
然而仅仅调用interrupt()
是不够的,守护进程线程必须主动检查该标志(使用isInterrupted()
)并正确响应,尽快关闭。此外,您还应正确处理中断异常(如果有)
您的线程是守护进程线程这一事实与此无关。非守护进程线程阻止JVM退出(当所有非守护进程线程完成其工作时JVM存在)。在这里,您手动中断线程-不管该线程是否为守护进程
这仅仅是一个垃圾收集器延迟,还是线程永远不会结束,因为主对象没有被删除,因为它被reporter引用
您的“报告…”
消息是否显示过?您可以在那里设置断点。这意味着实现finalize()
的对象是GC的受害者。如果只有reporter
thread持有对主对象的引用(反之亦然),尽管存在循环依赖关系,但如果没有外部引用这些对象,GC仍将释放这些对象
另见:
log.info("Reporting of {} is about to interrupt", getName());
我注意到,报告线程并没有结束,尽管它是在主线程中编码的
由于异常或返回,线程在完成run()
方法时结束。如果您谈论的是thread.interrupt()
,那么这只是设置中断标志,并导致一些方法(sleep、wait等)抛出InterruptedException
。在线程中,您需要测试中断标志:
while (!Thread.currentThread().isInterrupted()) {
// here's how you should be catching InterruptedException
try {
...
} catch (InterruptedException e) {
// re-enable the interrupted flag
Thread.currentThread.interrupt();
// probably you should quit the thread too
return;
}
}
一旦线程完成并且没有人对线程
对象本身有引用,垃圾回收器就会获取该线程。如果main仍然有一个线程
字段,那么它将永远不会被垃圾收集
顺便说一句,不鼓励使用finalize
,尤其是当您在那里登录和做其他事情时。您应该有自己的destroy()
方法,或者在线程结束时执行类似清理的方法。可能是这样的:
public void run() {
try {
// do the thread stuff
} finally {
destroy();
}
}
我注意到,报告线程并没有结束,尽管它是在主线程中编码的
由于异常或返回,线程在完成run()
方法时结束。如果您谈论的是thread.interrupt()
,那么这只是设置中断标志,并导致一些方法(sleep、wait等)抛出InterruptedException
。在线程中,您需要测试中断标志:
while (!Thread.currentThread().isInterrupted()) {
// here's how you should be catching InterruptedException
try {
...
} catch (InterruptedException e) {
// re-enable the interrupted flag
Thread.currentThread.interrupt();
// probably you should quit the thread too
return;
}
}
一旦线程完成并且没有人对线程
对象本身有引用,垃圾回收器就会获取该线程。如果main仍然有一个线程
字段,那么它将永远不会被垃圾收集
顺便说一句,不鼓励使用finalize
,尤其是当您在那里登录和做其他事情时。您应该有自己的destroy()
方法,或者在线程结束时执行类似清理的方法。可能是这样的:
public void run() {
try {
// do the thread stuff
} finally {
destroy();
}
}
您确定它不应该是线程对象的引用,以便它成为GC吗?对于其他对象,这是不正确的:如果对象具有相互引用,它们仍然是垃圾收集的。我不能拥有自己的
destroy()
,因为我没有地方叫它。我有主线程对象,我可以随时调用它们,然后就把它们忘了。目前,他们应该垃圾收集和相关记者应该停止。你可能会考虑不要忘记他们。可能在分叉时保留一组线程,以便您可以清理它们。您确定它是正确的吗