Java线程和垃圾收集器
可能重复:Java线程和垃圾收集器,java,multithreading,garbage-collection,Java,Multithreading,Garbage Collection,可能重复: 考虑以下类别: class Foo implements Runnable { public Foo () { Thread th = new Thread (this); th.start(); } public run() { ... // long task } } 如果我们通过 new Foo(); new Foo(); new Foo(); new Foo(); (请注意,我们没有保留指向它们的指针) 垃圾收集
考虑以下类别:
class Foo implements Runnable {
public Foo () {
Thread th = new Thread (this);
th.start();
}
public run() {
... // long task
}
}
如果我们通过
new Foo();
new Foo();
new Foo();
new Foo();
(请注意,我们没有保留指向它们的指针)
run()
中的线程结束了吗?(换句话说:是否有任何参考
到Foo
对象?)Foo
对象。线程在运行期间始终被引用。因此,它不会被垃圾收集Foo
对象Customer c = new Customer();
Customer
的构造函数运行时可能会失败。另一方面,当您启动一个新线程时,thread对象将成为一个新的GC根,因此该对象引用的所有内容都不会被垃圾收集
- 从单元测试的角度来看,在构造函数中启动一个新线程是一个糟糕的想法
- 保留对所有正在运行的线程的引用可能是有益的,例如,如果您想稍后中断这些线程
run()
出于任何原因返回时),该线程将从线程组中删除。这发生在从本机代码调用的私有方法exit()
中。这是对线程的最后一次引用丢失并符合GC条件的时间点
请注意,代码表明
ThreadGroup
可以是null
,但事实并非如此。各种空检查只是为了在出现问题的罕见情况下避免NPE。在Thread.init()
中,如果Java无法确定线程组,您将获得NPE。假设您在run方法中创建对象,则当run方法退出时,对象将超出范围,然后可用于垃圾收集。Run只是另一种方法。无论是否使用线程,都不会以任何方式改变此处的垃圾收集行为。您需要关心的是对象何时超出范围,这通常与块范围(方法块、while循环、if块等)有关
因此,由于您一开始没有保留对对象的任何引用,因此您可能希望将创建对象的逻辑提取到它自己的短期方法中。这样创建的对象就不需要超出该方法的范围 @MarkoTopolnik:哦,是的!OP正在将
这个
传递给线程
构造函数,该构造函数恰好是Foo
的一个实例。然而,这是正确的-如果Foo
有一些状态,所有状态变量都将在GC中生存,因为它们被Foo
引用,而Foo
被线程本身引用。从线程安全的角度来看,在构造函数中启动新线程也是一个糟糕的主意。在这种简单的情况下,可能会出现问题,但如果您对该类进行子类化,并在子类构造函数中初始化了一些最终字段,则在访问它们之前可能不会对它们进行初始化。Foo对象不是在run方法中创建的,而是在main中创建的。只是另一个代码块,你可以很容易地测试它。@Quaternion,可能是的,但另一个问题的措辞真的很“模糊”,很难理解,imho。这不是重复的。链接的问题并没有涉及“在完成之后它是否会被垃圾收集”(我正要特别问这个问题)。它只询问/回答“它在运行时不会被GC’ed”这一方面。在我看来,这个问题更好。这就是游戏化内容监管的结果。东西被标记为重复的,但它显然不是。请告诉我你从哪里得到这个结论。