【问题标题】:Does a dereferenced Java object still get garbage-collected if it started a thread which is still running?如果取消引用的 Java 对象启动了仍在运行的线程,它是否仍会被垃圾回收?
【发布时间】:2012-08-26 09:14:40
【问题描述】:

考虑以下场景:

  • 对象myObj 在某个函数myFunc本地实例化。
  • myObj 启动一个线程 someThread,它运行一些后台任务,例如从套接字读取。
  • myFunc 然后返回,导致 myObj 被取消引用。

在正常情况下,JVM 只会垃圾收集myObj。但是,如果someThread 还在运行,还会是这样吗?

我知道someThread 本身不会被 GC,只要它仍在运行,但在我的代码中它还需要访问存储在myObj,所以我确保 myObj 在它仍在运行时仍然存在是很重要的。

【问题讨论】:

  • Java 虚拟机规范不保证 anything 被垃圾回收。您使用的是什么特定的 JVM?
  • @veer 我打算在 Linux 上的 Oracle JVM 上运行完成的代码。我想问myObj 是否仍然 在线程运行时被垃圾收集更合适。在这种情况下,我需要确保某些东西不会得到 GC,而不是相反。
  • @Positronized 如果你的线程以某种方式可以访问一个对象,它必须有一个对它的引用。如果你有一个对象的引用,它就不能被垃圾回收。

标签: java multithreading garbage-collection


【解决方案1】:

一个对象只有在没有对它的引用时才有资格进行垃圾回收。你说someThread 需要访问存储在myObj 中的值,这意味着它必须引用myObj。这意味着 myObj 不符合垃圾回收条件,除非 someThread 也符合条件。

你可以保证一个对象永远不会从你下面被垃圾收集,例如,这是非常安全的:

void foo() {
    final Object something = new String("I'm alive!");
    new Thread() {
        public void run() {
            try {Thread.sleep(10000);} catch (InterruptedException e) {}
            System.out.println(something);
        }
    }.start();
}

something 被匿名线程引用,因此在匿名线程完成之前,它没有资格进行垃圾回收。

更具体地说,对于您的示例,这也是安全的:

void foo() {
    new ThreadStartingObject("I'm alive!");
}

class ThreadStartingObject {
    private String message;

    public void ThreadStartingObject(String msg) {
        this.message = msg;
        new Thread() {
            public void run() {
                try {Thread.sleep(10000);} catch (InterruptedException e) {}
                System.out.println(message);
            }
        }.start();
    }
}

代表线程的匿名内部类隐式引用了外部this,即ThreadStartingObject的实例。该引用会阻止垃圾收集。

【讨论】:

  • 如果我在myObj 的构造函数中使用(new Thread(new Runnable() { ... })).start() 启动线程,这样对myObj 的唯一引用是通过this,它还算数吗?
  • 是的。任何引用都会阻止垃圾收集。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
相关资源
最近更新 更多