1

我已经更改了文本,所以一些评论可能参考以前的版本

下面是代码示例。有两个线程:observer 和 observable。Observable 由 main 启动。观察者由可观察对象的创建开始,并以它的销毁结束。但它不会发生,观察者会永远运行。为什么?

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");

}
}
4

2 回答 2

2

当您的主对象(覆盖的对象finalize())不再可访问(有资格进行垃圾收集)时,GC 将finalize()首先调用。我看到您正在跟踪它,因此请确保您的日志消息实际上已被调用。

然而仅仅调用interrupt()是不够的,守护线程必须主动检查该标志(使用isInterrupted())并正确响应它,尽快关闭。如果有的话,你也应该正确处理InterruptedException

您的线程是守护线程这一事实无关紧要。非守护线程阻止 JVM 退出(当所有非守护线程完成工作时,JVM 存在)。在这里,您手动中断线程 - 该线程是否为守护进程并不重要。

这只是垃圾收集器延迟还是线程真的永远不会结束,因为主对象因为被报告者引用而没有被删除?

您的"Reporting of..."消息是否显示过?你可以在那里放一个断点。这意味着实现的对象finalize()是 GC 的受害者。如果只有reporter线程持有对您的主对象的引用(反之亦然),如果它们都没有被外部引用,GC 仍将释放这些对象,尽管循环依赖。

也可以看看:

后经

与你的问题无关。如果您使用的是,则:

log.info(String.format("Reporting of (%s) is about ot interrupt", getName()));

可以替换为:

log.info("Reporting of {} is about to interrupt", getName());
于 2012-07-26T17:26:59.350 回答
2

我注意到,尽管它是在主线程中编码的,但记者线程并没有结束

run()当一个线程由于异常或返回而完成该方法时结束。如果您正在谈论,thread.interrupt()那么这只是设置中断标志并导致某些方法(睡眠,等待,...) throw 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;
     }
}

一旦线程完成并且没有人引用Thread对象本身,垃圾收集器将回收该线程。如果 main 仍然有一个Thread thread字段,那么它将永远不会被垃圾收集。

顺便说一句,finalize真的不鼓励使用 - 特别是如果你在那里记录和做其他事情。你应该有你自己的destroy()方法或一些这样的方法,当线程完成时进行那种清理。也许是这样的:

 public void run() {
     try {
        // do the thread stuff
     } finally {
        destroy();
     }
 }
于 2012-07-26T17:27:03.277 回答