当Java中的线程从内存中删除时?

Par*_*agJ 6 java memory garbage-collection jvm memory-management

从Java API doc:

Java虚拟机继续执行线程,直到发生以下情况:

所有非守护程序线程的线程都已死亡,无论是通过从run方法调用返回还是抛出传播超出run方法的异常.

我希望我的假设是正确的,一旦线程完成其run()方法,它就有资格进行垃圾收集.在同样的背景下,我只是想知道:

  1. 如果它在返回后没有资格进行垃圾收集run(),那么应该设置它的引用null吗?
  2. 符合垃圾收集条件并不一定意味着该对象将从内存中删除.当垃圾收集时,它由底层操作系统/ JVM自行决定.但是如何确保(通过Java程序或外部工具)对象完全从内存中删除?
  3. 如果一个线程一旦完成run()方法就被认为是死的,为什么我仍然能够执行isAlive()getState()在同一个线程对象上?无论是调用返回falseRUNNABLE 分别.

Pet*_*rey 9

Thread类是真正的线程是在本机内存的代理.

我希望我的假设是正确的,一旦线程完成其run()方法,它就有资格进行垃圾收集.

run()之后实际上有一些代码,这段代码处理未捕获的异常.

一旦线程死亡,其本机内存和堆栈将立即释放,而无需GC.然而,该Thread对象就像任何其他对象一样,它一直存在,直到GC已经确定它可以是免费的,例如没有强烈的引用它.

同样,FileOutputStream是操作系统中文件的代理.即使在文件被close()删除甚至删除后,您仍然可以引用该对象.

如果从run()返回后它没有资格进行垃圾收集,那么应该将其引用设置为null来执行此操作吗?

你很少需要在任何地方这样做.实际上,通常更简单的是不首先保留对线程的引用,或者使用ExecutorService来管理线程.

当我有一个具有Thread字段的对象时,我经常会在线程死亡时使该对象死亡,因此不需要null输出该字段.

我还使用用于Fork/Join的内置线程池.这是一种在后台线程中执行任务的更轻量级的方法,因为它不会如此多地创建和销毁线程.

ExecutorService fjp = ForkJoinPool.commonPool();
Run Code Online (Sandbox Code Playgroud)

符合垃圾收集条件并不一定意味着该对象将从内存中删除.当垃圾收集时,它由底层操作系统/ JVM自行决定.但是如何确保(通过Java程序或外部工具)对象完全从内存中删除?

你不能,一般不应该尝试.GC将在需要时清理资源.

如果一个线程一旦完成run()方法就被认为是死的,为什么我仍然可以在同一个线程对象上执行isAlive()或getState()?两个调用分别返回false和RUNNABLE.

线程对象就像任何其他对象一样.只要您拥有对它的引用,就可以在其上调用方法.


Mar*_*nik 5

似乎您正在绊倒 Java 中难以理解的线程的常见陷阱:线程本身不是 Java 对象。它是本机资源(执行线程)。它将在运行完代码后立即“从内存中删除”。

Thread另一方面,的实例只是一个普通 Java 对象,与任何其他对象具有相同的生命周期——除了一个额外的规则,即它至少在底层本地线程处于活动状态时保持可达。您始终可以调用Thread.currentThread().

因此,如果您保留对Thread负责死线程的实例的引用,它不会神奇地消失,并且其所有方法将继续按指定的方式运行。您可以根据需要一直坚持下去。

关于您的问题 2,从记忆中“删除”一个对象实际上是一个毫无意义的术语。运行时本身实际上并不知道收集到的对象——它们是那些它已经忘记的对象。