一、简单案例
cs
private void buttonThreads_Click(object sender, EventArgs e)
{
Log.Info($"btnThread_Click_Start {Thread.CurrentThread.ManagedThreadId}");
ThreadStart threadStart = () => this.DoSomethingLong("btnThread_Start");
Thread thread = new Thread(threadStart);
thread.Start();
Log.Info($"btnThread_Click_End {Thread.CurrentThread.ManagedThreadId}");
}
private void DoSomethingLong(string name)
{
Log.Info($"DoSomethingLong Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
long result = 0;
for (int i = 0; i < 10000000; i++)
{
result += i;
}
Thread.Sleep(2000);
Log.Info($"DoSomethingLong End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
注意:现在不建议使用thread.Suspend();//线程挂起
和thread.Resum(); //唤醒线程
thread.Abort(); //销毁,方法是抛异常,也不建议使用
二、常用API介绍
1、Join 线程等待
csthread.Join(500);//最多等待500毫秒 thread.Join(); //当前线程等待thread完成
2、thread.ThreadState; //线程状态
3、thread.IsBackground;
(i)默认是前台线程,启动之后一定要完成任务的,阻止进程退出。
(ii)如果使用后台线程,只要进程退出了线程也就退出了,现在一般都建议使用后台线程,因为不会卡界面。
4、thread.Priority;
(i)线程优先级,可以设置5个等级 CPU会优先执行ThreadPriority。
(ii)但是不代表它会最先完成
二、Thread的问题
线程池--享元模式--数据库连接池
1、thread提供了太多的API
2、无限使用线程,需要加以限制
3、重用线程,避免重复的创建和销毁
三、线程池
cs
private void buttonQueue_Click(object sender, EventArgs e)
{
Log.Info($"DoSomethingLong Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
ThreadPool.QueueUserWorkItem(t => this.DoSomethingLong("btnThreadPool_Click"));
Log.Info($"DoSomethingLong End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
private void DoSomethingLong(string name)
{
Log.Info($"DoSomethingLong Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
long result = 0;
for (int i = 0; i < 10000000; i++)
{
result += i;
}
Thread.Sleep(2000);
Log.Info($"DoSomethingLong End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
1、手动限制线程池内的数量
cs
private void buttonQueue_Click(object sender, EventArgs e)
{
Log.Info($"DoSomethingLong Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
ThreadPool.QueueUserWorkItem(t => this.DoSomethingLong("btnThreadPool_Click"));
{
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
Log.Info($"线程池中辅助线程最大数目={workerThreads} 线程池中异步IO线程的最大数目={completionPortThreads}");
}
{
ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
Log.Info($"线程池中辅助线程最小数目={workerThreads} 线程池中异步IO线程的最小数目={completionPortThreads}");
}
ThreadPool.SetMaxThreads(16, 16);
ThreadPool.SetMinThreads(8, 8);
{
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
Log.Info($"线程池中辅助线程最大数目={workerThreads} 线程池中异步IO线程的最大数目={completionPortThreads}");
}
{
ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
Log.Info($"线程池中辅助线程最小数目={workerThreads} 线程池中异步IO线程的最小数目={completionPortThreads}");
}
Log.Info($"DoSomethingLong End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
ThreadPool啥也没有,不能控制线程的开始,暂停,恢复等功能
四、线程池等待
1、类 包含了一个bool属性
初始化为false -- WaitOne 等待 -- Set -- true--WaitOne直接过去
true--WaitOne直接过去--Reset -- false -- WaitOne等待
cs
private void buttonQueue_Click(object sender, EventArgs e)
{
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t =>
{
this.DoSomethingLong("btnThreadPool_Click");
manualResetEvent.Set();
});
manualResetEvent.WaitOne();
}
五、线程池阻塞(死锁)
cs
private void button小案例_Click(object sender, EventArgs e)
{
{
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
Console.WriteLine(workerThreads + " " + completionPortThreads);
}
ThreadPool.SetMaxThreads(20, 20);
ThreadPool.SetMinThreads(8, 8);
{
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
Console.WriteLine(workerThreads + " " + completionPortThreads);
}
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
for (int i = 0; i < 28; i++)
{
int k = i;
ThreadPool.QueueUserWorkItem(t =>
{
Console.WriteLine(k);
if (k < 20)
{
manualResetEvent.WaitOne();
}
else
{
manualResetEvent.Set();
}
});
}
if (manualResetEvent.WaitOne())
{
Console.WriteLine("没有死锁");
}
}
这段代码里我限定了线程池里边只有20个线程,而我for循环里调用了超过20个,所以产生了线程死锁问题。
**原因:**我们在使用阻塞方法的时候没有把线程Set回去
csprivate void buttonQueue_Click(object sender, EventArgs e) { ManualResetEvent manualResetEvent = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(t => { this.DoSomethingLong("btnThreadPool_Click"); //这里应该Set回去 manualResetEvent.Set(); }); manualResetEvent.WaitOne(); }