这篇文章介绍了C#多线程之线程池线程池的用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
目录
一、ThreadPool1、QueueUserWorkItem()2、GetMaxThreads()3、GetMinThreads()4、SetMaxThreads()和SetMinThreads()二、线程等待三、线程重用
一、ThreadPool
线程池是100 .净框架2.0版本中出现的。
线程池出现的背景:线程功能繁多,而且对线程数量没有管控,对于线程的开辟和销毁要消耗大量的资源。每次新的一个线都要重新开辟内存。
如果某个线程的创建和销毁的代价比较高,同时这个对象还可以反复使用的,就需要一个池子(容器),保存多个这样的对象,需要用的时候从池子里面获取,用完之后不用销毁,在放到池子里面。这样不但能节省内存资源,提高性能,而且还能管控线程的总数量,防止滥用。这时就需要使用线程池了。
我们来看看线程池中常用的一些方法。
1、QueueUserWorkItem()
QueueUserWorkItem()方法用来启动一个多线程。我们先看看方法的定义:
QueueUserWorkItem()方法有一个等待回调类型的参数,在看看等待回调的定义:
可以看到等待回调就是有一个目标类型参数的委托,所以线程池启动多线程使用下面的代码:
使用系统;
使用系统。穿线;
命名空间线程池演示
{
班级计划
{
静态void Main(string[] args)
{
控制台WriteLine($ ' start ThreadId:{ Thread .当前线程。managedthreadid。tostring(' 00 ')} ');
//线程轮询启动多线程
线程池QueueUserWorkItem(p=dosometinglong(' m启动多线程'));
控制台WriteLine($ ' end ThreadId:{ Thread .当前线程。managedthreadid。tostring(' 00 ')} ');
控制台read key();
}
静态void DoSomethingLong(字符串段落)
{
控制台WriteLine($ ' { para } ThreadId:{ Thread .当前线程。managedthreadid。tostring(' 00 ')} ');
}
}
}
运行结果:
2、GetMaxThreads()
GetMaxThreads()用来获取线程池中最多可以有多少个辅助线程和最多有多少个异步线程。
线程池get max threads(out int worker threads,out int completionPortThreads);
控制台WriteLine($ ' GetMaxThreads worker threads={ worker threads } completionPortThreads={ completionPortThreads } ');
程序运行结果:
3、GetMinThreads()
GetMinThreads()用来获取线程池中最少可以有多少个辅助线程和最少有多少个异步线程。
线程池GetMinThreads(out int minworkerThreads,out int mincompletionPortThreads);
控制台. WriteLine($ ' GetMinThreads worker threads={ minworkerThreads } completionPortThreads={ mincompletionPortThreads } ');
程序运行结果:
4、SetMaxThreads()和SetMinThreads()
SetMaxThreads()和SetMinThreads()分别用来设置线程池中最多线程数和最少线程数。
使用系统;
使用系统。穿线;
命名空间线程池演示
{
班级计划
{
静态void Main(string[] args)
{
控制台WriteLine($ ' start ThreadId:{ Thread .当前线程。managedthreadid。tostring(' 00 ')} ');
//线程轮询启动多线程
线程池QueueUserWorkItem(p=dosometinglong(' m启动多线程'));
//获取最大线程
线程池get max threads(out int worker threads,out int completionPortThreads);
控制台WriteLine($ ' GetMaxThreads worker threads={ worker threads } completionPortThreads={ completionPortThreads } ');
//获取最小线程
线程池GetMinThreads(out int minworkerThreads,out int mincompletionPortThreads);
控制台. WriteLine($ ' GetMinThreads worker threads={ minworkerThreads } completionPortThreads={ mincompletionPortThreads } ');
//设置线程池线程
SetThreadPool();
//输出设置后的线程池线程个数
控制台(控制台).WriteLine('输出修改后的最多线程数和最少线程数');
线程池get ax threads(out int maxworkertthreads,out int maxcompletionportthreads):
控制台(控制台).writeline($ getmaxthreads workertthreads={ maxworkertthreads } completion port threads={ max completion port threads });
线程池get int threads(out int work heredthreads,out int completion porteditthreads):
控制台(控制台).writeline($ getminthreads workertthreads={ workerethreads } completion port threads={ completion port threads });
控制台(控制台).写入行($结束线程id:{ thread }。当前线程。已管理线程。tostring(' 00 ');
控制台(控制台).read key();
}
静态void dosomethinglong(字符串段落)
{
控制台(控制台).writeline($ para)线程id:{ thread .当前线程。已管理线程。tostring(' 00 ');
}
///摘要
///设置线程池线程个数
///摘要
静态void SetThreadPool()
{
控制台(控制台).写线(* * * * * * * * * * * * *设置最多线程数和最少线程数**本报告迟交是因为需要更多的资料。
//设置最大线程
线程池SetMaxThreads(16,16个线程);
//设置最小线程
线程池setminthread(8.8个);
}
}
}
程序运行结果:
二、线程等待
先来看下面一个小例子:
线程池queuserwork项(p=剂量学计算('启动多线程');
控制台(控制台).WriteLine('等着queueuserworkitem(伫列工作项目)完成后才执行');
我们想让异步多线程执行完以后再输出""等着queueuserworkitem(伫列工作项目)完成后才执行""这句话,上面的代码运行效果如下:
从截图中可以看出,效果并不是我们想要的,线程中提供了暂停~我爱你~恢复等蜜蜂,蜜蜂,但是线程池中没有这些蜜蜂,蜜蜂,在线程池中要实现线程等待,需要使用到手动重置事件类。
手动重置事件类的定义如下:
手动重置事件需要一个波儿类型的参数来表示暂停和停止。上面的代码修改如下:
//参数设置为假的
manual reset event=new manual reset event(false);
线程池queuserwork项(p=
{
陀螺仪('启动多线程');
//设置为真的吗
手动重置选择事件(罗马尼亚语)。set();
});
//
手动重置选择事件(罗马尼亚语)。wait one();
控制台(控制台).WriteLine('等着queueuserworkitem(伫列工作项目)完成后才执行');
结果:
手动重置事件类的参数值执行顺序如下:
(1)假-等待人等待-设置-没错-等等直接过去
(2)真-等一等直接过去-重设-错-等等等待
注意:一般情况下,不要阻塞线程池中的线程,因为这样会导致一些无法预见的错误。来看下面的一个例子:
静态查看SetWait()
{
//设置最大线程
线程池SetMaxThreads(16,16个线程);
//设置最小线程
线程池setminthread(8.8个);
manual reset event=new manual reset event(false);
for(int I=0);i 20(一)
{
int k=I;
线程池queuserwork项(p=
{
控制台(控制台).写线(k);
如果(k 18)
{
手动重置选择事件(罗马尼亚语)。wait one();
}
其他语句
{
//设为真的吗
手动重置选择事件(罗马尼亚语)。set();
}
});
}
if(manualreselectevent).WaitOne())
{
控制台(控制台).WriteLine('没有死锁“(a)’”:
}
其他语句
{
控制台(控制台).WriteLine('发生死锁“(a)’”:
}
}
启动20个线程,如果好的。对小于18就阻塞当前的线程,结果:
从截图中看出,只执行了16个线程,后面的线程没有执行,这是为什么呢?因为我们在上面设置了线程池中最多可以有16个线程,当16个线程都阻塞的时候,会造成死锁,所以后面的线程不会再执行了。
三、线程重用
线程池可以很好的实现线程的重用,这样就可以减少内存的消耗,看下面的代码:
///摘要
///测试线程池线程重用
////摘要
静态void ThreadPoolTest()
{
//线程重用
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程。睡眠(10 * 1000);
控制台WriteLine('前面的计算都完成了。');
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
线程池QueueUserWorkItem(t=dosometinglong('线程池'));
}
然后在主要的方法里面调用该方法,输出结果如下图所示:
我们在代码里面总共创建了10个线程,而结果里面只有四个线程ID,这就说明线程池可以实现线程的重用。下面我们在看看线是否可以实现线程的重用,代码如下:
///摘要
///测试线线程重用
////摘要
静态空线程测试()
{
for(int I=0;i5;我)
{
新线程(()=dosometinglong(' Threads ')).start();
}
线程。睡眠(10 * 1000);
控制台WriteLine('前面的计算都完成了。');
for(int I=0;i5;我)
{
新线程(()=dosometinglong(' BTN线程')).start();
}
}
然后在主要的方法里面调用,输入结果如下图所示:
我们同样在代码里面创建了10个线程,结果输出了10个线程的ID,这就说明线不能实现线程的重用。同样也说明线的效率没有线程池高。
程序完整代码:
使用系统;
使用系统。穿线;
命名空间线程池演示
{
班级计划
{
静态void Main(string[] args)
{
控制台WriteLine($ ' start ThreadId:{ Thread .当前线程。managedthreadid。tostring(' 00 ')} ');
////线程轮询启动多线程
//线程池QueueUserWorkItem(p=dosometinglong(' m启动多线程'));
////获取最大线程
//线程池get max threads(out int worker threads,out int completionPortThreads);
//控制台WriteLine($ ' GetMaxThreads worker threads={ worker threads } completionPortThreads={ completionPortThreads } ');
////获取最小线程
//线程池GetMinThreads(out int minworkerThreads,out int mincompletionPortThreads);
//控制台. WriteLine($ ' GetMinThreads worker threads={ minworkerThreads } completionPortThreads={ mincompletionPortThreads } ');
////设置线程池线程
//SetThreadPool();
////输出设置后的线程池线程个数
//控制台WriteLine('输出修改后的最多线程数和最少线程数');
//线程池get max threads(out int maxworkerThreads,out int maxcompletionPortThreads);
//控制台. WriteLine($ ' GetMaxThreads workerThreads={ maxworkerThreads } completionPortThreads={ maxcompletionPortThreads } ');
//线程池GetMinThreads(out int workerEditThreads,out int completionPortEditThreads);
//控制台WriteLine($ ' GetMinThreads worker threads={ workerEditThreads } completionPortThreads={ completionPortEditThreads } ');
//控制台WriteLine($ ' end ThreadId:{ Thread .当前线程。managedthreadid。tostring(' 00 ')} ');
////参数设置为错误的
//ManualResetEvent ManualResetEvent=new ManualResetEvent(false);
//线程池queuserwork项(p=
//
//陀螺仪('启动多线程');
////设置为真的吗
//manualResetEvent .set();
//}:
////
//manualResetEvent .wait one();
//控制台WriteLine('等着queueuserworkitem(伫列工作项目)完成后才执行');
//SetWait():
//线程池实现线程的重用
//ThreadPoolTest():
//线程
ThreadTest():
控制台(控制台).写入行($结束线程id:{ thread }。当前线程。已管理线程。tostring(' 00 ');
控制台(控制台).read key();
}
静态void dosomethinglong(字符串段落)
{
控制台(控制台).writeline($ para)线程id:{ thread .当前线程。已管理线程。tostring(' 00 ');
}
///摘要
///设置线程池线程个数
///摘要
静态void SetThreadPool()
{
控制台(控制台).写线(* * * * * * * * * * * * *设置最多线程数和最少线程数**本报告迟交是因为需要更多的资料。
//设置最大线程
线程池SetMaxThreads(16,16个线程);
//设置最小线程
线程池setminthread(8.8个);
}
静态查看SetWait()
{
//设置最大线程
线程池SetMaxThreads(16,16个线程);
//设置最小线程
线程池setminthread(8.8个);
manual reset event=new manual reset event(false);
for(int I=0);i 20(一)
{
int k=I;
线程池queuserwork项(p=
{
控制台(控制台).写线(k);
如果(k 18)
{
手动重置选择事件(罗马尼亚语)。wait one();
}
其他语句
{
//设为真的吗
手动重置选择事件(罗马尼亚语)。set();
}
});
}
if(manualreselectevent).WaitOne())
{
控制台(控制台).WriteLine('没有死锁“(a)’”:
}
其他语句
{
控制台(控制台).WriteLine('发生死锁“(a)’”:
}
}
///摘要
///测试线程池线程重用
///摘要
静态空的线程池测试()
{
//线程重用
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
执行绪。睡眠(10 * 1000);
控制台(控制台).WriteLine('前面的计算都完成了. ');
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
线程池queuserwork项(t=线程池):
}
///摘要
///测试线程数线程重用
///摘要
静态空的线程测试()
{
for(int I=0);i5;和:(一)
{
新线程(()=doomethinglong(' threads ').start();
}
执行绪。睡眠(10 * 1000);
控制台(控制台).WriteLine('前面的计算都完成了. ');
for(int I=0);i5;和:(一)
{
新线程(()=陀螺仪(' btnThreads ').start();
}
}
}
}
关于C#多线程的ThreadPool用法的文章到此结束。希望对大家的学习有帮助,也希望大家多多支持。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。