池化思想
如果某个对象创建和销毁代价比较高,同时这个对象还可以反复使用的,就需要一个池子保存多个这样的对象,需要用的时候从池子里面获取;用完之后不用销毁,放回池子。(享元模式)
线程池节约资源提升性能;此外,还能管控总数量,防止滥用。
线程池使用
分配线程
WaitCallback waitCallback = o =>
{
Console.WriteLine(o);
this.DoSomethingLong("btnThreadpool_Click");
};
ThreadPool.QueueUserWorkItem(waitCallback);
ThreadPool.QueueUserWorkItem(waitCallback,"欢迎大家。。。");
设置线程池中线程的数量
ThreadPool.SetMinThreads(2, 2);
ThreadPool.SetMaxThreads(4, 4); //设置的最大值,不能小于计算机的逻辑线程数
ThreadPool.GetMinThreads(out int minworkerThreads, out int mincompletionPortThreads);
Console.WriteLine($"Min this minworkerThreads={minworkerThreads} this mincompletionPortThreads={mincompletionPortThreads}");
ThreadPool.GetMaxThreads(out int maxworkerThreads, out int maxcompletionPortThreads);
Console.WriteLine($"Min this maxworkerThreads={maxworkerThreads} this maxcompletionPortThreads={maxcompletionPortThreads}");
线程池里的线程我们可以设置,但是不要随便折腾;因为设置以后,线程相当于当前进程而言,是全局的;
Task Parallel都是来自于线程池; 但是new Thread 又可以新开一个线程;会占一个线程池的位置;
线程等待
通过ManualResetEvent 实现
- ManualResetEvent 默认要求参数状态false-----关闭;mre.Set()----打开
- ManualResetEvent 状态参数true----打开;mre.Reset()----关闭
ManualResetEvent mre = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(o =>
{
Console.WriteLine(o);
this.DoSomethingLong("欢迎大家。。。。");
mre.Set();//状态false----ture
//mre.Reset();
});
Console.WriteLine("do some thing else");
Console.WriteLine("do some thing else");
Console.WriteLine("do some thing else");
Console.WriteLine("do some thing else");
mre.WaitOne();//只要是mre状态编程true;就继续往后执行;
Console.WriteLine("任务全部完成了。。。。。");
线程死锁
循环个数超过线程池中的线程数量,每一个都在等待,导致线程死锁
ThreadPool.SetMaxThreads(12, 12);
ManualResetEvent mre = new ManualResetEvent(false);
for (int i = 0; i < 15; i++)
{
int k = i;
ThreadPool.QueueUserWorkItem(t =>
{
Console.WriteLine($"ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")} {k}");
if (k == 14)
{
mre.Set();
}
else
{
mre.WaitOne();
}
});
}
if (mre.WaitOne()) //只有在mre.Set();执行以后,状态值为true,才能往后执行;
{
Console.WriteLine("所有任务执行完成。。。。。。");
}