【问题标题】:Java Multithreading: Behaviour when Reference count of thread object becomes zeroJava多线程:线程对象的引用计数变为零时的行为
【发布时间】:2012-07-16 07:21:23
【问题描述】:

[在我开始之前我尝试搜索相关问题,因为我没有找到,所以我在这里问一个问题]

我正在学习 Java,下面的场景突然出现在我的脑海中:

class MyThread extends Thread {
    void run(){
        //a heavy function
    }
}

现在在主线程中,我将这个线程调用为:

public static void main(...){
    new MyThread().start();
    System.gc(); //just a request..
    //end of main thread too.
    //Reference to that MyThread object is now zero.
}

我运行了那个代码。看来线程还活着。当所有线程退出时,程序结束。

我的问题:

  • 当引用计数为零时,线程是否有资格进行GC?如果真的符合条件,那么垃圾回收的行为是什么?线程会被终止吗?
  • 我知道这是一件坏事,但在 main() 中没有 otherThread.join() 是否定义明确?

我对自己有一些解释(但我不知道我有多正确——我在这里发帖的原因):

  • 只要线程活动,JVM 就会维护对线程的引用。所以引用计数永远不会是零。
  • 正在执行的函数有一个隐式的this 引用,所以引用计数又不是零。

我在上述任何解释中是否正确?还是完全有其他解释?

感谢和问候:)

【问题讨论】:

    标签: java multithreading garbage-collection reference-counting


    【解决方案1】:

    每个正在运行的线程构成 GC 的根。从根之一可到达的任何对象都不符合 GC 条件,并且线程具有对 java.lang.Thread 实例的线程本地引用(由 Thread.currentThread() 返回)。所以不,您的线程在结束运行之前不会被 GC,因为可以从正在运行的线程访问 Thread 实例。

    我不明白为什么不在生成的线程上调用join() 会是一件坏事。如果您不在乎生成的线程何时结束,则无需加入它。当最后一个非守护线程停止运行时,应用程序将停止。

    另外,请注意,引用的数量并不是 GC 用来判断对象是否符合 GC 条件的数量。如果图不再可访问,则保持相互引用的对象图(例如 DOM 树)可以进行 GC。

    【讨论】:

    • +1 JLS 并没有说 JVM 不会使用引用计数。由于已知的限制,AFAIK 没有这样做。
    • 我认为第一句话有点不对劲。我们必须特别注意将Thread 实例与实际执行线程区分开来。 new Thread() 创建线程,该实例的 GC-ing 也不会神奇地停止线程 --- 不会超过 new File() 的 GCing 将删除磁盘上的文件。正确的答案是有一个可通过Thread.currentThread() 访问的线程本地引用,这使得Thread 实例在底层线程执行时始终可以访问。
    • @MarkoTopolnik:我编辑了答案以添加此信息。我使用“正在运行的线程”而不是“线程实例”来明确我的意思是执行线程,而不是 java.lang.Thread 的实例。可能还不够清楚。
    【解决方案2】:

    1. JVM will terminate only when all the Non-Daemon thread including the Main thread 已终止。 (主线程不是 main() 方法)。

    2. 线程在运行完它的 run() 方法后会立即死亡,但是正如您所知道的,每个线程(脚趾,即线程of execution) 与 Thread 类的 Instance 相关联。

    3.所以当线程死亡时,它会进入死亡状态(我这里没有提到线程池),但是与线程相关联的线程类的对象线程仍然存在,但已永久失去其线程。

    4.但是很有可能你的线程仍然在运行,只有 main 方法完成了。

    5. 调用join() 一点也不坏,但应谨慎使用。

    【讨论】:

    • 每个线程都是 Thread 类的一个实例。 “与线程关联的对象”和“永久失去其线程性”是没有意义的。
    • @EJP 如果您在我的回答中对这些行有疑问,请向Head First Java, and thats Kathy Sierra and Berth Bate 的作者投诉。他们可能是你真正的罪魁祸首............
    【解决方案3】:

    当引用计数为零时,线程是否有资格进行GC?

    没有。当线程终止并且没有引用时,它就有资格进行 GC。

    如果真的符合条件,那么垃圾回收的行为是什么?线程会被终止吗?

    见上文。

    我知道这是一件坏事,但它是否明确定义为 main() 中没有 otherThread.join()?

    这不是一件坏事,而且它的定义非常明确:当所有非守护线程都退出时,JVM 将退出。

    只要线程处于活动状态,JVM 就会保持对线程的引用。所以引用计数永远不会是零。

    正确。

    正在执行的函数有一个隐含的 this 引用,所以引用计数也不为零。

    不正确。考虑静态方法。根据定义,执行函数是在活动线程中执行的,因此根据定义,线程是活动的,因此它不能被 GC 处理。你在这里的想法是相当循环的。

    【讨论】:

    • 感谢一百万 @EJP :)。我希望这与这里的其他答案一样多。
    猜你喜欢
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多