关于Task.Factory.StartNew线程池归还及队列任务检查的技术疑问
嘿,让我逐个拆解你的问题:
默认情况下,当你用Task.Factory.StartNew()且不指定特殊创建选项时,任务会交给线程池调度器处理。一旦任务的委托代码执行完毕,对应的线程池线程就会被归还到线程池,等着被后续任务复用。
不过有个例外:如果你指定了TaskCreationOptions.LongRunning参数,CLR会专门创建一个非线程池的独立线程来跑这个任务。这种情况下,线程在任务结束后会直接被销毁,不会回到线程池。
这个判断完全正确。
道理很简单:线程(不管是线程池线程还是LongRunning的独立线程)会被绑定到这个任务,直到任务彻底执行完成。而你的代码里是while(true)的无限循环——哪怕有Thread.Sleep,也只是让线程暂时休眠,并没有终止任务的运行。只要这个循环不退出,任务就会一直处于“运行中”状态,对应的线程就会被一直占用,根本没机会归还线程池(如果是线程池线程),也不会被销毁(如果是独立线程),直到整个进程终止。
这得看你用的队列具体是怎么实现的,结合你代码里的PlayWithQueue类,给你几个实用方案:
给自定义队列加状态属性:如果
PlayWithQueue是你自己写的,直接给它加个公开属性来暴露队列状态就行,比如用ConcurrentQueue的话:public class PlayWithQueue { private readonly ConcurrentQueue<Action> _taskQueue = new ConcurrentQueue<Action>(); // 你的AddToQueueForExecution方法... // 检查是否有待执行任务 public bool HasPendingTasks => !_taskQueue.IsEmpty; // 或者想知道具体数量:public int PendingTaskCount => _taskQueue.Count; }之后你就可以通过
s.HasPendingTasks轻松判断了。用队列自身的方法判断:如果用的是
ConcurrentQueue这类线程安全队列,也可以调用TryPeek(out _)——如果返回true,就说明队列里还有待处理的任务:// 假设_taskQueue是PlayWithQueue里的私有队列,你可以封装成方法或者暴露出来 if (s._taskQueue.TryPeek(out _)) { // 存在待执行任务 }如果是线程池的任务队列:很遗憾,.NET没有公开直接访问线程池内部队列的API。这种情况下你要么自定义
TaskScheduler来跟踪任务,要么用系统性能计数器(比如“ThreadPool Queue Length”)来间接查看队列长度。
附上你提供的代码片段:
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Helper h = new Helper(); PlayWithQueue s = new PlayWithQueue(); s.AddToQueueForExecution(() => { h.Indicate(1); }); s.AddToQueueForExecution(() => { h.Indicate(2); }); s.AddToQueueForExecution(() => { h... } } }
内容的提问来源于stack exchange,提问作者A191919




