所以工作线程由开发人员调用,I/O线程由CLR调用。所以通常情况下,开发者并不会直接用到它。因此可以认为,工作者线程和I/O线程没有区别,它们都是普通的线程,但是CLR线程池中区分它们的目的是为了避免线程都去处理I/O回调而被耗尽,从而引发死锁。(设想,所有的工作者线程每一个都去等待I/O异步完成。)
static bool QueueUserWorkItem(WaitCallback callBack)
:参数为一个带一个object
类型参数的委托,最后返回bool
值成功则返回true
class ThreadPoolTest
{
static void Main()
{
Console.WriteLine("启动多线程...");
for(int i = 0; i <10; i++)
{
ThreadPool.QueueUserWorkItem( p => printStr("当前线程") );
}
Console.WriteLine("结束多线程...");
Console.ReadKey();
}
private static void printStr(string str)
{
Console.WriteLine("{0}是:{1}", str, Thread.CurrentThread.ManagedThreadId);
}
}
输出结果, 可以看到有很多线程ID是重复的,这就是线程池的强大之处了
启动多线程...
结束多线程...
当前线程是:8
当前线程是:6
当前线程是:10
当前线程是:9
当前线程是:7
当前线程是:11
当前线程是:12
当前线程是:9
当前线程是:6
当前线程是:10
class ThreadPoolTest
{
static void Main()
{
// 获取默认的线程池中的最大,最小线程数
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
Console.WriteLine("最大线程数,工作线程:{0}, IO线程数:{1}", maxWorkerThreads, maxCompletionPortThreads);
ThreadPool.GetMinThreads(out int minWorkerThreads, out int minCompletionPortThreads);
Console.WriteLine("最小线程数,工作线程:{0}, IO线程数:{1}", minWorkerThreads, minCompletionPortThreads);
// 重新设置最大、最小线程数
ThreadPool.SetMaxThreads(10, 10);
ThreadPool.SetMinThreads(3, 3);
// 获取默认的线程池中的最大,最小线程数
ThreadPool.GetMaxThreads(out int newMaxWorkThread, out int newMaxIOThread);
Console.WriteLine("重新设置后的最大线程数,工作线程:{0}, IO线程数:{1}", newMaxWorkThread, newMaxIOThread);
ThreadPool.GetMinThreads(out int newMinWorkThread, out int newMinIOThread);
Console.WriteLine("重新设置后的最小线程数,工作线程:{0}, IO线程数:{1}", newMinWorkThread, newMinIOThread);
Console.WriteLine("启动多线程...");
for(int i = 0; i <10; i++)
{
ThreadPool.QueueUserWorkItem( p => printStr("当前线程") );
}
Console.WriteLine("结束多线程...");
Console.ReadKey();
}
private static void printStr(string str)
{
Console.WriteLine("{0}是:{1}", str, Thread.CurrentThread.ManagedThreadId);
}
}
输出结果
最大线程数,工作线程:32767, IO线程数:1000
最小线程数,工作线程:8, IO线程数:8
重新设置后的最大线程数,工作线程:10, IO线程数:10
重新设置后的最小线程数,工作线程:3, IO线程数:3
启动多线程...
结束多线程...
当前线程是:6
当前线程是:9
当前线程是:7
当前线程是:8
当前线程是:11
当前线程是:10
当前线程是:12
当前线程是:11
当前线程是:7
当前线程是:9
查看系统cpu的处理数
需要使用到ManualResetEvent类
ManualResetEvent需要一个bool类型的参数来表示暂停和停止
class ThreadPoolTest2
{
// 参数设置为false
static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
static void Main()
{
Console.WriteLine("启动多线程...");
ThreadPool.QueueUserWorkItem(p => printStr("当前线程"));
// 等待 线程池执行任务完成
manualResetEvent.WaitOne();
Console.WriteLine("结束多线程...");
}
private static void printStr(string str)
{
Console.WriteLine("{0}是:{1}", str, Thread.CurrentThread.ManagedThreadId);
// 设置为true
manualResetEvent.Set();
}
}
输出结果
启动多线程...
当前线程是:6
结束多线程...
注:一般情况下,不要阻塞线程池中的线程,因为写代码无意间造成的线程等待没有释放,一旦线程池线程耗尽就会形成死锁
造成死锁的案例: 设置了最大线程数是9,循环创建15个线程,意味着 后6个线程必然需要利用线程池中前面用过的线程, 但是由于前面创建的线程都直接让阻塞了,没有释放,这时循环到第10个线程时由于没有空闲线程,线程池没法执行就直接跳过了,主线程会继续执行后面的循环,这样也永远不会 执行 manualResetEvent.Set() 方法,最后就成死锁了
private static void Test1()
{
// 设置最大线程
ThreadPool.SetMaxThreads(9, 9);
// 设置最小线程
ThreadPool.SetMinThreads(3, 3);
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
for (int i = 0; i < 15; i++)
{
int k = i;
ThreadPool.QueueUserWorkItem(p =>
{
Console.WriteLine(k);
if (k < 10)
{
manualResetEvent.WaitOne();
}
else
{
// 设为true
manualResetEvent.Set();
}
});
}
if (manualResetEvent.WaitOne())
{
Console.WriteLine("没有死锁。。。。。。。。。");
}
Console.WriteLine("结束。。。。。。。。。。");
}
输出结果
1
0
2
3
4
5
6
7
8
更多**好看的内容**和**好玩的案例**请关注**我的微信公众号: 程序猿知秋**