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方式,因为它会保持很多额外的线程。

此处摘录一段来自网络的参考:

As for the ThreadPool, it is designed to use as few threads as possible while also keeping the CPU busy. Ideally, the number of busy threads is equal to the number of CPU cores. However, if the pool detects that its threads are currently not using the CPU (sleeping, or waiting for another thread), it starts up more threads (at a rate of 1/second, up to some maximum) to keep the CPU busy.

多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比的更多相关文章

  1. Java值创建线程的两种方式对比

    在Java中创建线程的方式有两种,第一种是直接继承Thead类,另一种是实现Runable接口.那么这两种方式孰优孰劣呢? 采用继承Thead类实现多线程: 优势:编写简单,如果需要访问当前线程,只需 ...

  2. C# 读取Excel到DataTable两种方式对比

    方式一 OLEDB读取 数据库引擎 优点:读取速度快,依据sheet排序读取 缺点:对于Excel版本依赖强,无法读取指定sheet 错误提示:本地计算机未指定 Microsoft.ACE.OLEDB ...

  3. python格式化输出的两种方式对比

    1.%符号方法和format()函数方法 2.对比: 1 print('我今年%d岁' %22.125) 2 print('我今年{0:f}'.format(22.125)) 3 #报错 4 #槽中类 ...

  4. Java实现线程的两种方式?Thread类实现了Runnable接口吗?

    Thread类实现了Runnable接口吗? 我们看看源码中对与Thread类的部分声明 public class Thread implements Runnable { /* Make sure ...

  5. 创建线程的两种方式比较Thread VS Runnable

    1.首先来说说创建线程的两种方式 一种方式是继承Thread类,并重写run()方法 public class MyThread extends Thread{ @Override public vo ...

  6. Java实现多线程的两种方式

    实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...

  7. 创建线程的两种方式:继承Thread类和实现Runnable接口

    第一种方式:继承Thread类 步骤:1.定义类继承Thread 2.覆写Threa类的run方法. 自定义代码放在run方法中,让线程运行 3.调用线程的star方法, 该线程有两个作用:启动线程, ...

  8. Java中实现多线程的两种方式之间的区别

    Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...

  9. Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比--转载

     在加载大量数据的时候,经常会用到异步加载,所谓异步加载,就是把耗时的工作放到子线程里执行,当数据加载完毕的时候再到主线程进行UI刷新.在数据量非常大的情况下,我们通常会使用两种技术来进行异步加载,一 ...

随机推荐

  1. P1879 [USACO06NOV]玉米田Corn Fields 状压dp/插头dp

    正解:状压dp/插头dp 解题报告: 链接! ……我真的太菜了……我以为一个小时前要搞完的题目调错误调了一个小时……90分到100我差不多搞了一个小时…… 然后这题还是做过的……就很气,觉得确实是要搞 ...

  2. vuex是什么?怎么使用?哪种功能场景使用它?

    vuex是vue框架中状态管理.在main.js引入store,注入.新建了一个目录store,...export.应用场景有:单页应用中,组件之间的状态.应用实例:音乐播放.登录状态.加入购物车等等

  3. SpringBoot-Jar打包方式

    发布打包 Jar类型打包方式 1.使用mvn celan  package 打包 2.使用java –jar 包名 war类型打包方式 1.使用mvn celan package 打包 2.使用jav ...

  4. MongoDB limit 选取 skip跳过 sort排序 方法

    MongoDB  limit 选取 skip跳过 sort排序 在mysql里有order by  MongoDB用sort代替order by > db.user.find() { " ...

  5. what's the python之自定义模块和包

    模块自定义 上节说了有关模块的知识,当时所说的模块都是内置模块,现在来看自己定制的模块,即模块也可以自定义. 模块的自定义就是指写一段python文件,一般情况下里面包含了可执行的语句和函数的定义,其 ...

  6. emq共享订阅

    emqtt 试用(二)验证 emq 和 mosquito 的共享订阅 1. 多个订阅者都订阅以下主题形式 clientA 订阅  $queue/topic 发布主题名称为 topic1   clien ...

  7. pycharm tips

    批量更改变量名,就在该变量名上shift+f6 ../data 两个点,就是上一级目录,一个点就是当前目录 unhashable type: 'list' 使用set进行去重 a = [1,2,2,3 ...

  8. openvpn-服务端配置文件

    ;local a.b.c.d port 1194 ;proto tcp proto udp ;dev tap dev tun ;dev-node MyTap ca /etc/openvpn/keys/ ...

  9. python list成员函数extend与append的区别

    extend 原文解释,是以list中元素形式加入到列表中 extend list by appending elements from the iterable append(obj) 是将整个ob ...

  10. 从零开始一起学习SLAM | 学习SLAM到底需要学什么?

    SLAM涉及的知识面很广,我简单总结了 “SLAM知识树” 如下所示: (公众号菜单栏回复 “树” 可获得清晰版) 可以看到涉及的知识面还是比较广的.这里放出一张SLAM圈子里喜闻乐见的表达悲喜交加心 ...