This question was posted on some site. I didnt find right answers there, so I am posting it here again.
这个问题发布在某个网站上。我没有在那里找到正确的答案,所以我再次在这里发布。
public class TestThread {
public static void main(String[] s) {
// anonymous class extends Thread
Thread t = new Thread() {
public void run() {
// infinite loop
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
// as long as this line printed out, you know it is alive.
System.out.println("thread is running...");
}
}
};
t.start(); // Line A
t = null; // Line B
// no more references for Thread t
// another infinite loop
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.gc();
System.out.println("Executed System.gc()");
} // The program will run forever until you use ^C to stop it
}
}
My query is not about stopping a Thread. Let me rephrase my question. Line A(see code above) starts a new Thread; and Line B make the thread reference null. So, the JVM now has a Thread Object(which is in running state) to which no reference exists (as t=null in Line B). So my question is, why does this thread(that has no reference anymore in the main thread) keeps on running until the main thread is running. Per my understanding, the thread object should have been garbage collected post Line B. I tried to run this code for 5 minutes and more, requesting Java Runtime to run GC, but the thread just does not stop.
我的查询不是关于停止线程。让我重新解释一下我的问题。 A行(见上面的代码)启动一个新线程;和B行使线程引用为null。因此,JVM现在有一个没有引用的线程对象(处于运行状态)(在线B中为t = null)。所以我的问题是,为什么这个线程(主线程中没有引用)继续运行直到主线程运行。根据我的理解,线程对象应该在B行后进行垃圾收集。我尝试运行此代码5分钟以上,请求Java运行时运行GC,但线程不会停止。
Hope both the code and question is clear this time.
希望这次代码和问题都清楚。
4 个解决方案
#1
105
A running thread is considered a so called garbage collection root and is one of those things keeping stuff from being garbage collected. When the garbage collector determines whether your object is 'reachable' or not, it is always doing so using the set of garbage collector roots as reference points.
正在运行的线程被认为是所谓的垃圾收集根,并且是阻止垃圾收集的东西之一。当垃圾收集器确定您的对象是否“可访问”时,它总是使用垃圾收集器根集合作为参考点。
Consider this, why is your main thread not being garbage collected, no one is referencing that one either.
考虑一下,为什么你的主线程没有被垃圾收集,也没有人引用那个。
#2
20
As was explained, running threads are, by definition, immune to GC. The GC begins its work by scanning "roots", which are deemed always reachable; roots include global variables ("static fields" in Java-talk) and the stacks of all running threads (it can be imagined that the stack of a running thread references the corresponding Thread
instance).
如上所述,根据定义,运行线程对GC免疫。 GC通过扫描“根”开始工作,这些“根”被认为总是可以到达的;根包括全局变量(Java-talk中的“静态字段”)和所有正在运行的线程的堆栈(可以想象正在运行的线程的堆栈引用相应的Thread实例)。
However, you can make a thread a "daemon" thread (see Thread.setDaemon(boolean)
). A daemon thread is no more garbage-collected than a non-daemon thread, but the JVM exits when all running threads are daemon. One way to imagine it is that every thread, when it terminates, checks whether there remain some non-daemon running threads; if not, the terminating thread forces a System.exit()
call, which exits the JVM (killing off the running daemon threads). This is not a GC-related issue; in a way, threads are allocated manually. However, this is how the JVM can tolerate semi-rogue threads. This is typically used for Timer
instances.
但是,您可以将线程设置为“守护程序”线程(请参阅Thread.setDaemon(boolean))。守护程序线程不会比非守护程序线程更多地进行垃圾收集,但是当所有正在运行的线程都是守护程序时,JVM会退出。想象一下的一种方法是每个线程在终止时检查是否还有一些非守护进程正在运行的线程;如果不是,则终止线程强制执行System.exit()调用,该调用将退出JVM(终止正在运行的守护程序线程)。这不是与GC相关的问题;在某种程度上,线程是手动分配的。但是,这就是JVM可以容忍半流氓线程的方式。这通常用于Timer实例。
#3
16
The JVM has a reference to all running threads.
JVM引用了所有正在运行的线程。
No thread (or the things it refers to) will be garbage-collected while it is still running.
没有线程(或它引用的东西)在它仍在运行时将被垃圾收集。
#4
9
The Thread is not garbage collected because there are references to the threads that you cannot see. For example, there are references in the runtime system.
线程不是垃圾回收,因为有对您无法看到的线程的引用。例如,运行时系统中有引用。
When the Thread is created it is added to the current thread group. You can get a list of Threads in the current thread group, so that is another way to get a reference to it.
创建线程时,它将添加到当前线程组。您可以在当前线程组中获取线程列表,这是获取对它的引用的另一种方法。
#1
105
A running thread is considered a so called garbage collection root and is one of those things keeping stuff from being garbage collected. When the garbage collector determines whether your object is 'reachable' or not, it is always doing so using the set of garbage collector roots as reference points.
正在运行的线程被认为是所谓的垃圾收集根,并且是阻止垃圾收集的东西之一。当垃圾收集器确定您的对象是否“可访问”时,它总是使用垃圾收集器根集合作为参考点。
Consider this, why is your main thread not being garbage collected, no one is referencing that one either.
考虑一下,为什么你的主线程没有被垃圾收集,也没有人引用那个。
#2
20
As was explained, running threads are, by definition, immune to GC. The GC begins its work by scanning "roots", which are deemed always reachable; roots include global variables ("static fields" in Java-talk) and the stacks of all running threads (it can be imagined that the stack of a running thread references the corresponding Thread
instance).
如上所述,根据定义,运行线程对GC免疫。 GC通过扫描“根”开始工作,这些“根”被认为总是可以到达的;根包括全局变量(Java-talk中的“静态字段”)和所有正在运行的线程的堆栈(可以想象正在运行的线程的堆栈引用相应的Thread实例)。
However, you can make a thread a "daemon" thread (see Thread.setDaemon(boolean)
). A daemon thread is no more garbage-collected than a non-daemon thread, but the JVM exits when all running threads are daemon. One way to imagine it is that every thread, when it terminates, checks whether there remain some non-daemon running threads; if not, the terminating thread forces a System.exit()
call, which exits the JVM (killing off the running daemon threads). This is not a GC-related issue; in a way, threads are allocated manually. However, this is how the JVM can tolerate semi-rogue threads. This is typically used for Timer
instances.
但是,您可以将线程设置为“守护程序”线程(请参阅Thread.setDaemon(boolean))。守护程序线程不会比非守护程序线程更多地进行垃圾收集,但是当所有正在运行的线程都是守护程序时,JVM会退出。想象一下的一种方法是每个线程在终止时检查是否还有一些非守护进程正在运行的线程;如果不是,则终止线程强制执行System.exit()调用,该调用将退出JVM(终止正在运行的守护程序线程)。这不是与GC相关的问题;在某种程度上,线程是手动分配的。但是,这就是JVM可以容忍半流氓线程的方式。这通常用于Timer实例。
#3
16
The JVM has a reference to all running threads.
JVM引用了所有正在运行的线程。
No thread (or the things it refers to) will be garbage-collected while it is still running.
没有线程(或它引用的东西)在它仍在运行时将被垃圾收集。
#4
9
The Thread is not garbage collected because there are references to the threads that you cannot see. For example, there are references in the runtime system.
线程不是垃圾回收,因为有对您无法看到的线程的引用。例如,运行时系统中有引用。
When the Thread is created it is added to the current thread group. You can get a list of Threads in the current thread group, so that is another way to get a reference to it.
创建线程时,它将添加到当前线程组。您可以在当前线程组中获取线程列表,这是获取对它的引用的另一种方法。