多线程实现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方式,因为它会保持很多额外的线程。
此处摘录一段来自网络的参考:
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两种方式对比的更多相关文章
- Java值创建线程的两种方式对比
在Java中创建线程的方式有两种,第一种是直接继承Thead类,另一种是实现Runable接口.那么这两种方式孰优孰劣呢? 采用继承Thead类实现多线程: 优势:编写简单,如果需要访问当前线程,只需 ...
- C# 读取Excel到DataTable两种方式对比
方式一 OLEDB读取 数据库引擎 优点:读取速度快,依据sheet排序读取 缺点:对于Excel版本依赖强,无法读取指定sheet 错误提示:本地计算机未指定 Microsoft.ACE.OLEDB ...
- python格式化输出的两种方式对比
1.%符号方法和format()函数方法 2.对比: 1 print('我今年%d岁' %22.125) 2 print('我今年{0:f}'.format(22.125)) 3 #报错 4 #槽中类 ...
- Java实现线程的两种方式?Thread类实现了Runnable接口吗?
Thread类实现了Runnable接口吗? 我们看看源码中对与Thread类的部分声明 public class Thread implements Runnable { /* Make sure ...
- 创建线程的两种方式比较Thread VS Runnable
1.首先来说说创建线程的两种方式 一种方式是继承Thread类,并重写run()方法 public class MyThread extends Thread{ @Override public vo ...
- Java实现多线程的两种方式
实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...
- 创建线程的两种方式:继承Thread类和实现Runnable接口
第一种方式:继承Thread类 步骤:1.定义类继承Thread 2.覆写Threa类的run方法. 自定义代码放在run方法中,让线程运行 3.调用线程的star方法, 该线程有两个作用:启动线程, ...
- Java中实现多线程的两种方式之间的区别
Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比--转载
在加载大量数据的时候,经常会用到异步加载,所谓异步加载,就是把耗时的工作放到子线程里执行,当数据加载完毕的时候再到主线程进行UI刷新.在数据量非常大的情况下,我们通常会使用两种技术来进行异步加载,一 ...
随机推荐
- Js_protoType_原型
1.什么是原型? 之前在网上看了好多,各种说法的都有,说的很晦涩,很难理解,我觉得用的多了就会慢慢理解它的意思,总之来说,每个对象都有一个指向它原型,也就是每个对象都有原型. 2.原型有什么用? 原型 ...
- jquery.axios无刷新机制删除
思路:无刷新机制就是不用的刷新动作 ,用前端html语法删除和后端的数据库删,同时删除达到效果 除操作,来实现无刷洗的方法
- Ubuntu 远程挂载windows的分区
1.首先需要将windows需要挂载的分区设置为共享 2.在Ubuntu终端输入如下命令: sudo mount -t cifs -o username=***,password=*** //172. ...
- ubuntu上make menuconfig出错
如果使用make menuconfig的方式配置内核,又碰巧系统没有安装ncurses库(ubuntu系统默认就没有安装此库),就会出现错误,错误信息大体上如下: *** Unable to find ...
- IE8“开发人员工具”(下)
浏览器模式 说白了,就是让用户选择当前页面用何种IE版本去渲染. 文本模式 说起“文本模式”这个名词,这又要回到渲染页面的3种模式了:诡异模式(Quirks mode,也有翻译为兼容模式.怪异模式的) ...
- PHP 操作 Redis 的手册
转:https://www.cnblogs.com/jackluo/p/5708024.html String 类型操作 string是redis最基本的类型,而且string类型是二进制安全的.意思 ...
- su - 和su的区别
su root和su - root: su只是切换了root身份,但Shell环境仍然是普通用户的Shell:而su -连用户和Shell环境一起切换成root身份了 推荐使用su - .
- 基于UDP/TCP协议的套接字
1.UDP UDP的数据报协议特点是不粘包,非可靠传输 服务端 import socket server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ...
- HBase 数据迁移方案介绍 (转载)
原文地址:https://www.cnblogs.com/ballwql/p/hbase_data_transfer.html 一.前言 HBase数据迁移是很常见的操作,目前业界主要的迁移方式主要分 ...
- [vue]通过watch实现数据双向绑定
modal:单向绑定 <head> <meta charset="UTF-8"> <title>test</title> <s ...