每个线程都会分配有线程优先级。 在公共语言运行时内创建的线程初始分配有 ThreadPriority.Normal
的优先级。 在运行时外部创建的线程保留有在进入托管环境前的优先级。 若要获取或设置任意线程的优先级,可以使用 Thread.Priority
属性。
线程根据优先级被排入执行计划。 即使线程是在运行时内执行,操作系统也会为所有线程分配处理器时间片。 用于确定线程执行顺序的计划算法详细信息因每个操作系统而异。 在一些操作系统下,(在可以执行的线程中)优先级最高的线程始终都被计划为第一个运行。 如果有多个线程的优先级相同,计划程序会遍历具有此优先级的全部线程,为每个线程分配固定的执行时间片。 只要有更高优先级的线程可供运行,就不会执行优先级较低的线程。 如果在给定优先级没有其他任何可运行的线程,计划程序会转到下一个较低优先级,并计划执行具有此优先级的线程。 如果较高优先级的线程变得可运行,就会强占优先级较低的线程,并获准重新执行。 除此之外,如果应用的用户界面在前台和后台之间转换,操作系统还可以动态调整线程优先级。 其他操作系统可能会选择使用不同的计划算法。
示例
下面是从 Thread.Priority
枚举跨所有 5 个优先级执行 9 个线程示例,其中后 5 个线程位于最高优先级别。 此外,我们具有上一篇文章中的回调支持,它在此上下文中表明,后续代码和进程执行启动顺序都不会反映线程初始化和优先级排序的顺序。 这意味着,我们在此处看到了代码执行的并行性质,以及每个线程由操作系统分配的处理器时间切片的演示。 这突出显示了线程在其中运行的环境的影响和控制。 也就是说,我们肯定会看到最高优先级的线程确实在执行中获得了优先级。
以下代码将在每次执行时生成任意结果。 但在多次运行代码并分析输出后,可以观察到正在运行的优先级的常见序列模式。
namespace snippets; public class SchedulingThreads { public void RunMultipleThreadsOnDifferentPriorities() { var threadsList = new List<Thread>(9); // Initialize 9 threads. 5 with Highest priority, and the first 4 from Lowest to Normal range. for (int i = 0; i < 9; i++) { var thread = new Thread(() => { new ThreadWithCallback(Callback).Process(); }); if (i > 3) thread.Priority = ThreadPriority.Highest; else thread.Priority = (ThreadPriority)i; threadsList.Add(thread); } threadsList.ForEach(thread => thread.Start()); } public void Callback(ThreadPriority threadPriority) { Console.WriteLine($"Callback in {threadPriority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}."); } public class ThreadWithCallback { public ThreadWithCallback(Action<ThreadPriority> callback) { this.callback = callback; } public Action<ThreadPriority> callback; public void Process() { Console.WriteLine($"Entered process in {Thread.CurrentThread.Priority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}."); Thread.Sleep(1000); Console.WriteLine($"Finished process in {Thread.CurrentThread.Priority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}."); if (callback != null) { callback(Thread.CurrentThread.Priority); } } } // The example displays the output like the following: // Entered process in Highest priority. ThreadId: 9. // Entered process in Highest priority. ThreadId: 12. // Entered process in Normal priority. ThreadId: 6. // Entered process in BelowNormal priority. ThreadId: 5. // Entered process in Lowest priority. ThreadId: 4. // Entered process in AboveNormal priority. ThreadId: 7. // Entered process in Highest priority. ThreadId: 11. // Entered process in Highest priority. ThreadId: 10. // Entered process in Highest priority. ThreadId: 8. // Finished process in Highest priority. ThreadId: 9. // Finished process in Highest priority. ThreadId: 12. // Finished process in Highest priority. ThreadId: 8. // Finished process in Highest priority. ThreadId: 10. // Callback in Highest priority. ThreadId: 10. // Finished process in AboveNormal priority. ThreadId: 7. // Callback in AboveNormal priority. ThreadId: 7. // Finished process in Lowest priority. ThreadId: 4. // Callback in Lowest priority. ThreadId: 4. // Finished process in Normal priority. ThreadId: 6. // Callback in Highest priority. ThreadId: 9. // Callback in Highest priority. ThreadId: 8. // Callback in Highest priority. ThreadId: 12. // Finished process in Highest priority. ThreadId: 11. // Callback in Highest priority. ThreadId: 11. // Callback in Normal priority. ThreadId: 6. // Finished process in BelowNormal priority. ThreadId: 5. // Callback in BelowNormal priority. ThreadId: 5. }