Thread与ThreadPool的内存之战

procyon-decompile-xxxxa.zip java -jar procyon-decompiler-0.5.36.jar xxx.class -o filename 立即下载

转载地址:http://www.cnblogs.com/hsapphire/archive/2011/03/09/1978600.html

Thread与ThreadPool使用的时候在内存里对象是如何分布的呢?
今天我们就从内存堆的角度分析下两者。
先上小白鼠代码:

  
static   void  Main( string [] args)         {              for  ( int  i  =   0 ; i  <   30 ; i ++ )             {                 Thread t  =   new  Thread( new  ThreadStart(ThreadProc));                 t.Name  =   " Overred_ "   +  i;                 t.Start();             }             Console.Read();         }          static   void  ThreadProc()         {              try             {                  for  ( int  i  =   0 ; i  <   10 ; i ++ )                 {                      Console.WriteLine( " {0}  Value:{1} " ,Thread.CurrentThread.Name,i);                 }                             }              catch  (Exception ex)             {                 Console.WriteLine(ex.Message);             }         }
以上代码非常简单,就是循环启动30个线程去执行同一个方法ThreadProc(),然后打印出结果。 现在提出问题1:当Main里的30个线程都把ThreadProc()方法执行完毕后,这些Threads是自动消亡还是被GC回收,还是变成DeadThread? 好,拿出我们的看家工具windbg,来debug一把。 首先启动我们的程序,然后打开windbg,然后F6,Attach我们的exe 1,加载mscorwks(.net 2.0或者以上)
  
0:003> .loadby sos mscorwks 

2,查看该程序的线程情况

0:003> !Threads
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for 
C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll - 
PDB symbol for mscorwks.dll not loaded
ThreadCount: 32
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 30
Hosted Runtime: no
                                      PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
   0    1 25e4 00518858      a020 Enabled  013f878c:013f9fe8 00514818     1 MTA
   2    2 24b8 00526f20      b220 Enabled  00000000:00000000 00514818     0 MTA (Finalizer)
XXXX    3    0 00533028      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    4    0 00536858      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    5    0 005385c8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    6    0 005393d0      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    7    0 00534fd8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    8    0 0053a5c0      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    9    0 0053b3c8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    a    0 0053bfc0      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    b    0 0053eba8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    c    0 00543370      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    d    0 00543b38      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    e    0 00544700      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX    f    0 00544ec8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   10    0 00545690      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   11    0 00545ee0      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   12    0 005466c0      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   13    0 00546a88      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   14    0 00546e50      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   15    0 00547218      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   16    0 005475e0      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   17    0 005479a8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   18    0 00547d70      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   19    0 00548138      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   1a    0 00548500      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   1b    0 005488c8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   1c    0 00548c90      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   1d    0 00549058      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   1e    0 00549420      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   1f    0 005497e8      9820 Enabled  00000000:00000000 00514818     0 Ukn
XXXX   20    0 00549bb0      9820 Enabled  00000000:00000000 00514818     0 Ukn


看红色加粗部分,我们总共有32个线程,而DeadThread为30个(其他2个为程序自身所有,其中一个BackgroundThread),先告诉你这30个死线程正式我们循环创建的线程,可以回答我提的第一个问题拉,没错,他们统统死拉,而且不会醒来,还占地方(不是永远占地方,待会我们用GC手动让它们消亡)。

3,然后我们继续看看内存堆上它们这些坏家伙如何分布:

0:003> !DumpHeap -type System.Threading -stat
total 155 objects
Statistics:
      MT    Count    TotalSize Class Name
79108930        1           32 System.Threading.ContextCallback
790fe284        2          144 System.Threading.ThreadAbortException
79124b74       30          600 System.Threading.ThreadHelper
79104de8       31         1116 System.Threading.ExecutionContext
790fe704       31         1736 System.Threading.Thread
791249e8       60         1920 System.Threading.ThreadStart
Total 155 objects
 
红色部分,31个Thread,对应着31个Context,每个线程在windows底层都是一个内核对象和一个栈空间,内核对象存放一些线程的统计信息,比如计数器以及一个上下文,就是我上次执行到那里等。而栈空间则是用来存放线程参数等。
 

4,我们来具体看下这些Thread们的MethodTable

0:003> !DumpHeap -MT 790fe704 
 Address       MT     Size
013c1708 790fe704       56     
013c178c 790fe704       56     
013c235c 790fe704       56     
013c2474 790fe704       56     
013c258c 790fe704       56     
013c26a4 790fe704       56     
013c27bc 790fe704       56     
013c28d4 790fe704       56     
013c29ec 790fe704       56     
013c2b04 790fe704       56     
013c2c1c 790fe704       56     
013c2d34 790fe704       56     
013c2e54 790fe704       56     
013c2f74 790fe704       56     
013c3094 790fe704       56     
013c31b4 790fe704       56     
013c32d4 790fe704       56     
013c33f4 790fe704       56     
013c3514 790fe704       56     
013c3634 790fe704       56     
013c3754 790fe704       56     
013c3874 790fe704       56     
013c3994 790fe704       56     
013c3ab4 790fe704       56     
013c3bd4 790fe704       56     
013c3cf4 790fe704       56     
013c3e14 790fe704       56     
013c3f34 790fe704       56     
013f8084 790fe704       56     
013f81a4 790fe704       56     
013f82c4 790fe704       56     
total 31 objects
Statistics:
      MT    Count    TotalSize Class Name
790fe704       31         1736 System.Threading.Thread
Total 31 objects
 

5,随便拿一个线程的Address来看看到底是谁占着我们的Thread而不让我们的GC回收掉



  
0:003> !GCRoot 013c3bd4 Note: Roots found on stacks may be false positives. Run "!help gcroot" for more info. Scan Thread 0 OSTHread 25e4 Scan Thread 2 OSTHread 24b8 DOMAIN(00514818):HANDLE(WeakSh):241298:Root:013c3bd4(System.Threading.Thread)

结果另我们很失望,他自己就是根,并没被其他任何对象所引用,什么情况下会出现此情况呢?我们先来看看对象在内存中分布的几种方式,我们只需在windbg里执行如下命令则知:

0:003> !Help gcroot
-------------------------------------------------------------------------------
!GCRoot [-nostacks]  < Object  address >
!GCRoot looks for references (or roots) to an object. These can exist in four
places:
   1. On the stack
   2. Within a GC Handle
   3. In an object ready for finalization
   4. As a member of an object found in 1, 2 or 3 above.

First, all stacks will be searched for roots, then handle tables, and finally
the freachable queue of the finalizer. Some caution about the stack roots: 
!GCRoot doesn't attempt to determine if a stack root it encountered is valid 
or is old (discarded) data. You would have to use !CLRStack and !U to 
disassemble the frame that the local or argument value belongs to in order to 
determine if it is still in use.
Because people often want to restrict the search to gc handles and freachable
objects, there is a -nostacks option.
 
windbg已经很清楚的告诉我们,
一个对象可以
1,在栈上
2,在一个GCHandle里(可以执行!GCHandles命令查看)
3, 在FinalizeQueue里
4,是一个对象的成员
难道对象就必定在以上的“四行”之中吗?答案是不一定,还有个Gchandleleaks,就是你在内存里看不到这个Handle,它已经leak。(这种也算在GCHandle里吧)。

回头我们接着说他自己没被其他任何对象所引用,自己就是个根,但是GC却不搭理它,为何?那就是他在GCHandle里,
 
0:003> !GCHandles
GC Handle Statistics:
Strong Handles: 14
Pinned Handles: 4
Async Pinned Handles: 0
Ref Count Handles: 0
Weak Long Handles: 0
Weak Short Handles: 31
Other Handles: 0
Statistics:
      MT    Count    TotalSize Class Name
790fd0f0        1           12 System.Object
790fcc48        1           24 System.Reflection.Assembly
790feba4        1           28 System.SharedStatics
790fe17c        1           72 System.ExecutionEngineException
790fe0e0        1           72 System.StackOverflowException
790fe044        1           72 System.OutOfMemoryException
790fed00        1          100 System.AppDomain
79100a18        4          144 System.Security.PermissionSet
790fe284        2          144 System.Threading.ThreadAbortException
790fe704       32         1792 System.Threading.Thread
7912d8f8        4         8736 System.Object[]
Total 49 objects

而且在FinalizeQueue里也有它的踪影:

 
0:003> !FinalizeQueue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 35 finalizable objects (00526658->005266e4)
generation 1 has 0 finalizable objects (00526658->00526658)
generation 2 has 0 finalizable objects (00526658->00526658)
Ready for finalization 0 objects (005266e4->005266e4)
Statistics:
      MT    Count    TotalSize Class Name
791037c0        1           20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
79103764        1           20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
79101444        2           40 Microsoft.Win32.SafeHandles.SafeFileHandle
790fe704       31         1736 System.Threading.Thread
Total 35 objects
 
下面就来解释下什么才可以在FinalizeQueue里出现呢?答案就是有身份的人,很有身份的人,享受特殊待遇的哦!
啥身份,就是自身实现拉析构函数。

啥待遇,就是GC两次才有可能把他们部分清理掉!为啥部分,是我们不知道windows到底何时去把所有的清理掉(赖皮阿)
具体原理大家可以看.net框架去,我这里不多说。
 

说到此,也就找到我们当初30个彪形大汉为啥赖着不走的原因拉,是在0代的第一次GC时候,他们被放进FinalizeQueue,等着第二次GC他们部分才会从内存堆上消亡。
为证明我们的观点,我们可以修改程序为 :

  
static   void  Main( string [] args)         {              for  ( int  i  =   0 ; i  <   30 ; i ++ )             {                 Thread t  =   new  Thread( new  ThreadStart(ThreadProc));                 t.Name  =   " Overred_ "   +  i;                 t.Start();             }             GC.Collect();             GC.Collect();             Console.Read();         }
首先声明一点就是当我们调用一次GC.Collect();时,并不是执行一次垃圾收集,只是告诉系统我要强制进行垃圾收集,系统听到这个命令后乖不乖那就不一定拉。
当我们用Reflector查看mscorlib对Thread实现的使用也会发现他实现拉析构:
  
     ~ Thread()     {          this .InternalFinalize();     }
 

来个虎头蛇尾吧,当我们把小白鼠程序使用ThreadPool修改为:

  static   void  Main( string [] args)
        {
             for  ( int  i  =   0 ; i  <   30 ; i ++ )
            {
                ThreadPool.QueueUserWorkItem( new  WaitCallback(ThreadProc));
            }
            Console.Read();
        }
         static    void  ThreadProc( object  o)
        {
             try
            {
                 for  ( int  i  =   0 ; i  <   10 ; i ++ )
                {
                     Console.WriteLine( "  Value:{0} " ,i);
                }
               
            }
             catch  (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
 
再用windbg查看线程时则为:

0:006> !Threads
*** ERROR: Symbol file could not be found.  Defaulted to export symbols 
for C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll - 
PDB symbol for mscorwks.dll not loaded
ThreadCount: 4
UnstartedThread: 0
BackgroundThread: 3
PendingThread: 0
DeadThread: 0

而FinalizeQueue则为:
0:006> !FinalizeQueue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 7 finalizable objects (00266658->00266674)
generation 1 has 0 finalizable objects (00266658->00266658)
generation 2 has 0 finalizable objects (00266658->00266658)
Ready for finalization 0 objects (00266674->00266674)
Statistics:
      MT    Count    TotalSize Class Name
791037c0        1           20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
79103764        1           20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
79101444        2           40 Microsoft.Win32.SafeHandles.SafeFileHandle
790fe704        3          168 System.Threading.Thread
Total 7 objects

那现在又出现问题拉,既然ThreadPool这么好,那我们为啥还使用Thread呢?这个问题就是ThreadPool有个GetMaxThreads,可以通过GetMaxThreads(out int workerThreads, out int completionPortThreads);方法获取到,如果线程池满拉,则会死锁更严重!
另:ThreadPool都为后台线程。
究竟使用那个,根据情况而定,理解拉内在的东西,一切表象就简单拉。
OK,到此吧。。。

希望本文能对你有所帮助,谢谢!


SpringBoot实战(二十八)集成 Collabora Online 实现在线编辑 阅读详情

相关推荐

PaddleOCR实战:从零开始打造专属OCR模型的完整指南

本文提供了一份从零开始使用PaddleOCR打造专属OCR模型的完整实战指南。内容涵盖环境搭建、数据标注与准备、模型训练与调优,以及最终的模型转换与部署。重点介绍了如何利用PaddleOCR进行模型训练,并整合PPOCRLabel等工具高效准备数据集,帮助开发者快速构建适用于特定场景的高精度OCR识别能力。

rl6adventurer的博客 733

windbg thread&threadpool 转

《你不常用的c#之五》:Thread与ThreadPool的内存之战 Thread与ThreadPool使用的时候在内存里对象是如何分布的呢? 今天我们就从内存堆的角度分析下两者。 先上小白鼠代码: staticvoidMain(string[]args) { for(inti=0;i<30;i+...

weixin_30552635的博客 445

ISO 15118-20标准深度解读【精简篇】

ISO 15118-2 是开创者,它解决了“如何让电动汽车充电像给手机充电一样简单(即插即用且自动付费)”的问题,为行业奠定了基础。 ISO 15118-20 是革新者,它站在前者的肩膀上,回答了一个更宏大的问题:“如何让电动汽车深度融入未来的能源系统和智慧城市?” 它不仅是充电协议,更是一个车网互动的综合能源管理协议。简单来说,ISO 15118-2 是关于“如何充电”,而 ISO 15118-20 是关于“如何智慧地使用和管理电动汽车这块大电池”。

网络安全的研究者、新能源行业的追求者 1928

Windows核心编程——》第十一章 线程池(The Windows Thread Pool)

线程池的目的就是为了减少创建和销毁线程的额外开销,利用已经存在的线程多次循环执行多个任务从而提高系统的处理能力. 线程池会自动地根据内制的算法增加或减少线程池中的线程或为程序增加新的线程池。 1.异步方法调用                                 异步方法调用有以下两种方法:                                 (1

liuxiaomao1988的专栏 1567

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码) 文章目录扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)理论讲解KF和EKF模型对比雅可比矩阵计算计算实例应用实例线性模型CV模型:CA模型非线性模型CTRV模型:CTRV实例(python)small demo抛物线demo飞机高度demoC++实例参考文献 我们上篇提到的卡尔曼滤波是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布

O_MMMM_O的博客 10万+

TPAMI 2025新作LRFormer复现笔记:我的Windows 11 + RTX 4090配置全流程

本文详细记录了在Windows 11系统下使用RTX 4090显卡复现TPAMI 2025顶会论文LRTransformer的完整流程,包括硬件配置、系统优化、Python环境搭建及模型训练中的常见问题解决方案。特别针对Windows平台特有的路径管理、CUDA版本冲突和显存优化等关键技术细节提供了实用指南,帮助开发者高效完成环境搭建和模型训练。

weixin_29094301的博客 412

线程死锁

线程死锁的产生 ​ 线程同步可以帮助我们解决多个线程操作同一个资源而导致数据不安全的问题,但线程同步也有可能产生隐患,假如一个线程中出现多个锁对象时,可能出现锁使用不当,导致锁与锁之前相互等待对方释放资源,从而形成一种 “相互等待”的僵局,这就是线程死锁。 例如哲学家吃饭 ​ 模拟线程死锁 public class DeadThread implements Runnable { Object obj1 = new Object(); Object obj2 = new

LYHLL_hh的博客 297

基于FMCW技术的毫米波雷达测速原理与应用

调频连续波(FMCW)技术是毫米波雷达中实现高精度测速的核心方法之一。本文详细介绍了FMCW测速的基本原理、信号处理流程以及在实际应用中的关键技术。通过分析FMCW雷达的多普勒效应和频率差测量方法,本文展示了如何利用FMCW技术实现目标速度的高精度检测。此外,本文还探讨了FMCW测速在自动驾驶、智能交通和工业自动化等领域的应用案例,为毫米波雷达开发者提供了理论支持和实践指导。

不谈枯燥公式,只聊雷达趋势。用大白话解读毫米波里的黑科技。 1137

WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册

本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载。 系列博文 《WinDbg 命令三部曲:(一)WinDbg 命令手册》 《WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册》 《WinDbg 命令三部曲:(三)WinDbg SOSEX 扩展命令手册》 导航目录 扩展加载命令 对象审查命令 数据结...

aijianxie8808的博客 571

metaRTC嵌入式webrtc编译指南

metaRTC编译支持qmake和cmake,qmake使用QT最为方便,新版本新增了cmake支持。 ...

metaRTC的博客 9518

数学建模预测模型——回归分析预测

作为预测模型的大块头,回归分析预测绝对是比较常用的预测模型的一种,下面是对该模型的学习,欢迎大家指正😊。

everything is possible,anything is OK. 1万+

使用WinDbg —— .NET篇 (五)

6.2  终结方法 C++语言里面有个概念叫做析构函数,析构函数的语法和C#的终结方法一样,都是通过“~” + 类名作为函数名。也有人把C#的终结方法叫做析构函数,然而我还是比较喜欢终结方法这种叫法,一者因为C#中的终结方法的执行机制跟C++的析构函数是完全不一样的,被称作析构函数容易混淆;二者因为终结方法编译后的模块中,生成的IL中能看到生成的方法名就叫做Finalize。 之前我们看到

ecjtu_luowei的专栏 1589

OpenCV计算机视觉实战(3)——计算机图像处理基础

本文全面介绍了计算机视觉和数字图像处理的基础知识。从最基本的像素概念入手,详细讲解了图像在计算机中的表示方式,包括RGB、CMYK等色彩空间的工作原理及其应用场景。还系统分析了常见图像和视频文件格式的特点,梳理了计算机图像处理技术的发展历程,并重点介绍了OpenCV这一强大的开源计算机视觉库的功能与应用领域。

qq_30167691的博客 1740

《你不常用的c#之五》:Thread与ThreadPool的内存之战

<br />Thread与ThreadPool使用的时候在内存里对象是如何分布的呢? <br />今天我们就从内存堆的角度分析下两者。 <br />先上小白鼠代码:<br />static void Main(string[] args) { for (int i = 0; i < 30; i++) { Thread t = new Thread(new ThreadStart(ThreadProc));

高学宝的专栏 2906

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C#多线程之Thread,ThreadPool,Task,Parallel

C#多线程之Thread,ThreadPool,Task,Parallel

鲤籽鲲的博客 5763

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

c# Thread、ThreadPool、Task有什么区别,什么时候用,以及Task的使用

c# Thread、ThreadPool、Task有什么区别,什么时候用,以及Task的使用 这三者都是为了处理耗时任务,且都是异步的。 Thread Thread就是Thread,需要自己调度,适合长跑型的操作。 ThreadPoll ThreadPool是Thread基础上的一个线程池,目的是减少频繁创建线程的开销。线程很贵,要开新的stack,要增加CPU上下文切换,所以Threa...

m0_37805255的博客 5247

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

c# Thread、ThreadPool、Task有什么区别

https://www.jianshu.com/p/22059d39328e 这三者都是为了处理耗时任务,都是异步的; 先说 Thread与ThreadPoll 前台线程:主程序必须等待线程执行完毕后才可退出程序。Thread默认为前台线程,也可以设置为后台线程 后台线程:主程序执行完毕后就退出,不管线程是否执行完毕。ThreadPool默认为后台线程 线程消耗:开启一个新线程,线程不做...

坚定的走 2614

Task、ThreadPool、Thread的区别和使用

这三者都是为了处理耗时任务,都是异步的; 先说 Thread与ThreadPoll 前台线程:主程序必须等待线程执行完毕后才可退出程序。Thread默认为前台线程,也可以设置为后台线程 后台线程:主程序执行完毕后就退出,不管线程是否执行完毕。ThreadPool默认为后台线程 线程消耗:开启一个新线程,线程不做任何操作,都要消耗1M左右的内存 ThreadPoll是线程池 其目的是为了减...

u011707861的博客 2231

C# 异步编程 Thread、ThreadPool、Task

C# 异步编程,一些基本概念Thread、ThreadPool、Task

Raink的博客 2860

C#中Thread、ThreadPool、Task等联系及区别

先说 Thread与ThreadPoll 前台线程:主程序必须等待线程执行完毕后才可退出程序。Thread默认为前台线程,也可以设置为后台线程 后台线程:主程序执行完毕后就退出,不管线程是否执行完毕。ThreadPool默认为后台线程 线程消耗:开启一个新线程,线程不做任何操作,都要消耗1M左右的内存 ThreadPoll是线程池 其目的是为了减少开启新线程消耗的资源(使用线程池中的空闲线...

八步赶蝉 1955

C# 中Thread、ThreadPool、Task的使用

C# 中Thread、ThreadPool、Task的使用

qq_41862555的博客 2011

c# Thread、ThreadPool、Task区别

已经好几天没坚持写文章了,每天都谴责一下自己,然后沉沉睡去,即将患上懒癌的人。

hellofengxia的博客 690

C#中Thread、ThreadPool、Task的区别

在.Net Framework中提供了Thread 、ThreadPool、Task三种类型都是为了处理耗时的任务,都是异步的; 对于Thread和ThreadPool而言: 前台线程:主程序必须等待线程执行完毕后才能推出程序,Thread默认为前台程序,可以设置为后台程序; 后台程序:...

chuiyuan9786的博客 2545
上一篇: 线程池学习之ThreadPool Class
下一篇: LEFT JOIN 去除重复
andycode
博客等级 码龄17年 12粉丝 80原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值