多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比

Thread.Start(),ThreadPool.QueueUserWorkItem都是在实现多线程并行编程时常用的方法。两种方式有何异同点,而又该如何取舍?

写一个Demo,分别用两种方式实现。观察各自的现象。 

一个WorkMan class,其内的method doSomething()是每次异步线程调用的方法。该方法只是随机的让线程休眠一段时间。

public void doSomething()
{
     OnBegin(new EventArgs()); // someone does something here var r = new Random(); int sleepTime = r.Next(3000, 180000);
     Thread.Sleep(900000);

    OnCompleted(new EventArgs());
}

doSomething

Thread.Start()方式实现

workThreads = new Thread[NUMBER_OF_THREADS]; for (var i = 0; i < NUMBER_OF_THREADS; i++)
{
    arrWorkMen[i] = new WorkMan() { 
        WorkStarted = true,
        InstanceID = startThreadNumber
    };

    arrWorkMen[i].BeginHandler += HandleTaskBegin;
    arrWorkMen[i].CompletedHandler += HandleTaskCompleted; // create a thread and attach to the object var st = new ThreadStart(arrWorkMen[i].doSomething);
    workThreads[i] = new Thread(st);

    startThreadNumber++;
} for (var i = 0; i < NUMBER_OF_THREADS; i++)
{
    Thread.Sleep(2000);
    workThreads[i].Start();
}                

Thread.Start()

ThreadPool.QueueUserWorkItem方式实现

for (var i = 0; i < NUMBER_OF_THREADS; i++)
{
    arrWorkMen[i] = new WorkMan()
    {
        WorkStarted = true,
        InstanceID = startThreadNumber
    };

    arrWorkMen[i].BeginHandler += HandleTaskBegin;
    arrWorkMen[i].CompletedHandler += HandleTaskCompleted;

    startThreadNumber++;
} for (var i = 0; i < NUMBER_OF_THREADS; i++)
{
    Thread.Sleep(2000);
     ThreadPool.QueueUserWorkItem(o => arrWorkMen[i].doSomething());
}        

ThreadPool.QueueUserWorkItem

观察两种方式下,线程创建和回收的情况。

 

同样的场景,每2秒钟发起一新的线程,且每一线程均休眠2分钟。Thread.Start()实现下,线程一路最高飙升到71个,然后随着2分钟后休眠线程的结束,线程个数始终在70、71之间徘徊。而ThreadPool.QueueUserWorkItem的实现下,线程个数到达最高73后,始终在72、73之间徘徊。

 

 

总体来说,做同样的事情。ThreadPool方式产生的线程数略高于Thread.Start()。Thread.Start()产生的线程在完成任务后,很快被系统所回收。而ThreadPool(线程池)方式下,线程在完成工作后会被保留一段时间以备resue。所以,当需求需要大量线程并发工作的时候,不建议使用ThreadPool方式,因为它会保持很多额外的线程。

 

玩咖指针 2020-03-22 14:23:45