我想知道如果在方法中声明本地线程会发生什么?通常,函数返回后,所有局部变量都将消失,因为它们都在Stack上分配。然而,似乎本地线程将是一个不同的故事。是对的吗?
public int A() {
Thread t = new Thread() {
doSomething();
}
t.start();
return -1;
}
答案 0 :(得分:14)
线程是它自己的GC根。因此,无论何时创建线程,无论其创建上下文如何,在其运行方法完成之前,它都不会准备好GC。即使本地方法完成且线程仍处于活动状态,也是如此。
示例:
public void doSomeAsync(){
Thread th = new Thread(new Runnable(){
public void run(){
Thread.sleep(500);
}
});
th.start();
//do something else quickly
}
在//do somethign else quickly
任何未转义的定义后,该方法将被标记为GC。线程th不会被标记为GC,并且正确地放置在具有自己的线程堆栈的堆上。
答案 1 :(得分:7)
约翰的答案很好,但我想我会补充一些细节。这是一个代码示例,我将用它来显示特定的变量用法。
public void startThread() {
long var1 = 10;
byte[] var2 = new byte[1024];
final byte[] var3 = new byte[1024];
final byte[] var4 = new byte[1024];
Thread thread = new Thread(new Runnable() {
private long var5 = 10;
private byte[] var6 = new byte[1024];
public void run() {
int var7 = 100;
byte[] var8 = new byte[1024];
System.out.println("Size of var4 is " + var4.length);
baz();
...
}
private void baz() {
long var9 = 2;
byte[] var10 = new byte[1024];
...
}
});
thread.start();
}
因此我们在线程周围分配了许多变量。我们还有Thread
对象本身以及线程正在运行的Runnable
目标。
startThread()
的本地,但关联的Thread
也由JVM管理。在run()
方法完成并且Thread
由JVM获取后,它只是GC'd。 Thread
为GC后,Thread
使用的所有字段都可以进行GC。Thread
完成后进行GC并且是GC。startThread()
的本地,并在堆栈上分配。当startThread()
方法完成并重复使用堆栈时,它将被覆盖。startThread()
的本地,并在堆上分配。它不能被线程使用,因为它不是final
。它可以在startThread()
完成后进行GC。startThread()
的本地,并在堆上分配。这是final
因此线程可以使用 ,但事实并非如此。它可以在startThread()
完成后进行GC。startThread()
的本地,并在堆上分配。这是final
,它由线程使用。在startThread()
方法完成和 Runnable
并且Thread
都是GC后,它只能是GC。Runnable
内部的本地字段,并作为Runnable
匿名类的一部分在堆上分配。在Runnable
完成后Runnable
和Thread
为GC后,可以进行GC。Runnable
内的一个本地字段,并在堆上分配。在Runnable
完成后Runnable
和Thread
为GC后,可以进行GC。run()
方法内部的本地字段,并在新线程的堆栈上分配。当run()
方法完成并重复使用堆栈时,它将被覆盖。run()
方法中的本地字段,并在堆上分配。在run()
方法完成后,它可以是GC。baz()
方法内部的本地字段,并在新线程的堆栈上分配。当baz()
方法完成并重复使用堆栈时,它将被覆盖。baz()
方法内部的本地字段,并在堆上分配。在baz()
方法完成后,它可以是GC。结合其他笔记:
startThread()
完成后可以进行GC。 Runnable
以及与之关联的所有变量也可以是GC。final long varX
中声明了startThread()
原语并在线程中使用,那么它必须在堆上分配而不堆栈。当startThread()
完成后,它仍然会被使用。答案 2 :(得分:0)
如果从本地上下文启动Thread,则该线程将继续执行,直到Runnable的run
方法已完成执行。
答案 3 :(得分:0)
如果变量是基元,那么它将在堆栈上并且在方法返回时将消失 - 但是你的线程的Runnable
实例(或包含线程内容的任何内容)将具有原始值的副本。
如果变量属于引用类型,则该对象在堆上分配并存在,直到不再有对它的引用为止,此时它有资格进行垃圾回收。该对象的引用在堆栈上,并且在方法返回时将消失,但与原语一样,线程的Runnable
将具有该相同引用的副本(并因此将保留那个对象活着)。
答案 4 :(得分:-1)
如果在方法中生成本地Thread
,则只有声明为final
的本地方法变量才会保留,直到Thread
完成。当Thread
完成其run()
方法时,线程及其从创建它的方法可用的任何最终变量将像其他所有内容一样被垃圾收集。
<强>澄清强>
在方法和final
方法完成之前,原始方法中使用的只有run()
个变量和生成的线程的run()
方法将避免被垃圾回收。如果线程没有访问变量,那么线程的存在将不会阻止变量在原始方法完成后被垃圾收集。
<强>参考强>
http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html