19

假设我有如下代码:

int Main()
{
    if (true)
    {
       new Thread(()=>
          {
              doSomeLengthyOperation();
          }).Start();
    }
    while (true)
    {
       //do nothing
    }
}

有 2 个线程,我将把执行 Main() 函数的线程称为 Main 线程,并将在“if”测试中新建的线程称为线程 A。

我的问题是,线程 A 什么时候被销毁?doSomeLenghtyOperation() 能否完成?

由于没有指向线程 A 的引用,是否会将其标记为垃圾回收的候选对象:

  1. 在“new Thread().Start()”语句本身完成后立即?
  2. 在“if(true)”范围退出后立即?
  3. doSomeLengthOperation() 运行完成后?
  4. 绝不?

我看到的所有示例都是 Main() 持有引用,然后是 Main 线程在退出之前等待加入线程 A。我很好奇上面代码的生命周期是多少。

提前致谢!

4

4 回答 4

14

Thread一旦不再使用该对象,即在调用该Start方法之后立即进行垃圾回收,该对象就可以进行垃圾回收。(但是它不会立即被收集,因为垃圾收集器在特定时间运行。)

然而,实际的线程并不依赖于Thread对象,即使Thread对象被收集,它也会继续运行。

如果 main 方法退出时线程仍在运行,则应用程序在线程完成之前不会结束,除非您已将线程标记为后台线程。

于 2010-09-13T09:36:14.340 回答
14

“线程”一词在这里可能意味着几件事:

  • System.Threading.Thread 对象(由创建new Thread()),
  • CLR 线程(托管线程),
  • 操作系统线程(非托管线程)。

一旦 Start() 方法完成,线程对象将成为 GC 的候选对象,因为不再有对它的引用。

在 doSomeLengthyOperation() 运行时,托管线程将保持活动状态。

引用 Microsoft MVP James Kovacs 的文章

托管线程的生命周期独立于创建它的 Thread 对象,这是一件非常好的事情,因为您不希望 GC 仅仅因为丢失对关联 Thread 对象的所有引用而终止仍在工作的线程。所以 GC 正在收集 Thread 对象,而不是实际的托管线程。

如果您想自己进行试验,本文还包含一些有用的代码示例。

理论上,操作系统线程与托管线程没有一对一的关系。来自MSDN

...复杂的主机可以使用 CLR Hosting API 针对同一操作系统线程调度许多托管线程,或在不同操作系统线程之间移动托管线程。

然而,在实践中,CLR 线程现在直接映射到 Windows 线程

于 2010-09-14T08:20:47.440 回答
10

线程 A 什么时候被销毁?

什么时候doSomeLengthyOperation结束。

doSomeLenghtyOperation() 是否能够完成

是的,即使主线程存在,因为它不是后台线程。如果在主线程存在时将IsBackground属性设置为true在启动线程之前,则该线程也将停止。

于 2010-09-13T09:37:30.657 回答
0

这是一个很好的问题!线程肯定会完成,您可以自己尝试。但是如果你同时调用 GC.Collect() 会变得有趣。根据 Richter 的 C# via CLR,它将被垃圾收集。

更新

我相信它不会被垃圾收集,因为 Thread.CurrentThread 通过引用将它保存在内存中。

于 2010-09-13T09:36:45.123 回答