目录:
- 为什么要使用线程池
- 简单的线程池操作
- 执行上下文
- 协作式取消
一、为什么要使用线程池:线程池概念理解
备注:线程池中的线程是后台线程。
1、为什么会有线程池?
因为创建线程和销毁线程相对来说需要消耗大量的时间和资源。 太多的线程会浪费内存。
操作系统需要在线程间来回切换,线程过多,有损性能。
2、线程池是什么?
线程池就是一个可持续性发展的线程集合,线程池内部维护着一个消息队列。
当一条方法名引用追加到线程池的队列中,线程池会提取当前项,派发给线程池中空闲的线程。
3、线程池创建线程策略?
- 如果线程池中没有线程,就创建一个线程。
- 如果并发的请求数过多,且请求速度超出线程池处理速度,就会创建额外线程。
- 如果线程完成任务,不会销毁,会进入空闲状态,等待下个请求的响应。
- 如果在一定的时间内没有接收到请求,超度空闲,就会自己醒来,终止自己,释放资源。
二、简单的线程池操作
我们上面提到过,线程池内维护的了一个消息队列,方法引用追加到队列中,线程池中的线程从队列中取出等待执行。
[SecuritySafeCritical] public static bool QueueUserWorkItem(WaitCallback callBack);
[SecuritySafeCritical] public static bool QueueUserWorkItem(WaitCallback callBack, object state);
委托:
[ComVisible(true)] public delegate void WaitCallback(object state);
所以,一个是参数为null,一个是需要传递实参的委托。要使用以上方式向队列中添加工作项,其实是将方法引用添加到队列中
1、我们定义一个符合 WaitCallback 规则的委托 一个参数且没有返回值
public static void WorkerFun(object flag) { Console.WriteLine("【WorkerFun】 doing ........"); for (int index = 10; index > 0; index--) { Console.WriteLine(" {0}s", index); Thread.Sleep(2000); } Console.WriteLine("【WorkerFun】end."); }
2、我们使用线程池进行异步调用
public void Run(string args) { Console.WriteLine("【Main】doing......"); if (ThreadPool.QueueUserWorkItem(WorkerFun)) { Console.WriteLine("Add pool success"); } Console.WriteLine("【Main】sleep 5s.");
Thread.Sleep(5000);
Console.WriteLine("【Main】end.");
}
运行结果:
主线程执行完毕,子线程自动关闭。所以说,线程池中的线程都是后台线程,优先级比较低。
二、执行上下文
1、为什么要有执行上下文 ?
线程在执行代码时,会受到上下文的影响。
上下文会从初始线程流向辅助线程,这样这整个线程使用相同的安全设置和宿主设置。
同样,辅助线程可以使用初始线程的逻辑上下文。
namespace System.Threading
//执行上下文 public sealed class ExecutionContext : IDisposable, ISerializable { //从当前线程捕获执行上下文 [SecuritySafeCritical] public static ExecutionContext Capture(); //是否取消了执行上下文的流动 public static bool IsFlowSuppressed(); //恢复执行上下文在异步线程之间的流动 public static void RestoreFlow(); //在当前线程上的指定执行上下文中运行某个方法 [SecurityCritical] public static void Run(ExecutionContext executionContext, ContextCallback callback, object state); //取消执行上下文在异步线程之间的流动 [SecurityCritical] public static AsyncFlowControl SuppressFlow(); //创建当前执行上下文的副本 [SecuritySafeCritical] public ExecutionContext CreateCopy(); [SecuritySafeCritical] public void Dispose(); [SecurityCritical] public void GetObjectData(SerializationInfo info, StreamingContext context); }
通过执行上下文我们来控制上下文的流动。
CallContext.LogicalSetData("Name", "sc"); //默认允许上下文进行流动 ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); //现在禁止流动 ExecutionContext.SuppressFlow(); ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); //恢复流动 ExecutionContext.RestoreFlow(); Console.ReadKey();
运行:第一行允许流动;第二行禁止流动
Name=sc
Name=
三、协作式取消和超时
需要取消的模式必须显示支持取消
//通知 System.Threading.CancellationToken,告知其应被取消 public sealed class CancellationTokenSource : IDisposable
CancellationTokenSource 管理 着取消相关的状态.
所谓协作式,首先我自己要支持取消,接收信号后任务终止。
private static void Count(System.Threading.CancellationToken token, int countto) { for (int count = 0; count < countto; count++) { Console.WriteLine("index:{0}", count); if (token.IsCancellationRequested) { Console.WriteLine("Count is cancelled {0}",count); break; } } }
主线程中,接收协作式取消命令,子线程检测到信号后,主动停止。
public void Run(string args) { System.Threading.CancellationTokenSource cts = new CancellationTokenSource(); //开启线程 ThreadPool.QueueUserWorkItem(state => Count(cts.Token, 10000000)); Console.WriteLine("Press <Enter> to cancel the operation"); Console.ReadLine(); cts.Cancel(); Console.ReadLine(); }
运行结果:主线程发出回车信号,子线程检测到信号后结束任务。