重新学C#编程161-Priority:多线程优先级设置

在学习ThreadStart时,做过2个线程的练习-输出奇数和偶数,每次结果不一样,说明这两个线程随机的交替进行。如果希望控制输出顺序,就要定义优先级。

在 C# 中线程的优先级使用线程的 Priority 属性设置即可,默认的优先级是 Normal

在设置优先级后,优先级高的线程将优先执行。但不能说优先级高的执行完毕才执行优先级低的。

优先级的值通过 ThreadPriority 枚举类型来设置,从低到高分别为LowestBelowNormalNormalAboveNormalHighest

对前一个练习做一下修改,设置每一个线程的优先级,控制执行顺序。

using System;
using System.Threading;
namespace Priority多线程优先级控制
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Priority多线程优先级控制");
      ThreadStart threadStart1 = new ThreadStart(showEven);
      Thread thread1 = new Thread(threadStart1);
      thread1.Priority = ThreadPriority.Normal;//定义线程优先级为普通

      ThreadStart threadStart2 = new ThreadStart(showOdd);
      Thread thread2 = new Thread(threadStart2);
      thread2.Priority = ThreadPriority.Highest;//定义线程优先级为最高

      thread1.Start();
      thread2.Start();
    }
    public static void showEven()
    {
      //Console.WriteLine("显示偶数");
      for(int i=2;i<=100;i+=2)
      {
        Console.Write(i + " ");
      }
    }
    public static void showOdd()
    {
      //Console.WriteLine("显示奇数");
      for (int i=1;i<=100;i+=2)
      {
        Console.Write(i + " ");
      }
    }
  }
}

每次运行,输出结果不完全一样,优先级别高的获得的执行次数相对多一点,但也不知等优先级别高的执行完毕才执行优先级别低的。这样一来即使定义了优先级,输出结果的顺序还是不可控的。

线程状态控制的方法包括暂停线程 (Sleep)、中断线程 (Interrupt)、挂起线程 (Suspend)、唤醒线程 (Resume)、终止线程 (Abort)。

改造一下前面的代码,加入sleep,完整代码如下

using System;
using System.Threading;
namespace sleep暂停线程
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("sleep暂停线程");
      ThreadStart threadStart1 = new ThreadStart(showEven);
      Thread thread1 = new Thread(threadStart1);
      ThreadStart threadStart2 = new ThreadStart(showOdd);
      Thread thread2 = new Thread(threadStart2);

      thread1.Start();
      thread2.Start();

    }
    public static void showEven()
    {
      for(int i=2;i<=100;i+=2)
      {
        Console.Write(i + " ");
        Thread.Sleep(1000);//先输出,再暂停
      }
    }
    public static void showOdd()
    {
      for(int i=1;i<=100;i+=2)
      {
        Thread.Sleep(1000);
        Console.Write(i + " ");
      }
    }
  }
}

输出结果是

虽然交替输出,但是每次运行结果还是不完全一样,说明sleep不能完全控制输出的顺序。

下面练习一下线程终止Abort。模拟发红包,初始有10个,每次发一个,当数量少于5个,就停止发放。

完整代码如下

using System;
using System.Threading;
namespace Abort线程终止练习
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Abort线程终止练习");
      ThreadStart threadStart = new ThreadStart(RedEnvelop);
      Thread thread = new Thread(threadStart);
      thread.Start();
    }
    public static int count = 10;
    public static void RedEnvelop()
    {
      //int count = 10;
      try
      {
        while (count > 0)
        {
          count--;
          if (count == 4)
          {
            //终止进程
            Console.WriteLine("红包暂停发放");
            //Thread.Sleep(1000);
            Thread.CurrentThread.Abort();

          }
          Console.WriteLine("还剩{0}个红包", count);
        }
      }
      catch (ThreadAbortException ex)
      {
        // ThreadAbortException要在Exception的前面,因为Exception能够匹配所有异常
        Console.WriteLine("Method1 ThreadAbortException: " + ex.ToString());
      }
      finally
      {
        Console.WriteLine("执行完毕!");
      }

    }
  }
}

目前,由于挂起线程 (Suspend) 和唤醒线程 (Resume) 的操作很容易造成线程的死锁状态,已经被弃用了,而是使用标识字段来设置线程挂起和唤醒的状态。

所谓线程死锁就是多个线程之间处于相互等待的状态。

线程分为前台线程后台线程,前台线程不用等主程序结束,后台线程则需要应用程序运行结束后才能结束。

此外,在应用程序运行结束后,后台线程即使没有运行完也会结束,前台线程必须等待自身线程运行结束后才会结束。

使用 Thread 对象的 IsBackground 属性来判断线程是否为后台线程。

还是做一个练习,对前一个项目程序判断是不是后台线程,如果不是,将其设置为后台线程

完整代码如下

using System;
using System.Threading;
namespace IsBackground是否为后台线程
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("IsBackground练习");
      ThreadStart threadStart = new ThreadStart(RedEnvelop);
      Thread thread = new Thread(threadStart);
      thread.Start();
      if(thread.IsBackground)
      {
        Console.WriteLine("是后台线程");
      }
      else
      {
        Console.WriteLine("不是后台线程");
        thread.IsBackground = true;
      }
    }
    public static int count = 10;
    public static void RedEnvelop()
    {
      //int count = 10;
      try
      {
        while (count > 0)
        {
          count--;
          if (count == 4)
          {
            //终止进程
            Console.WriteLine("红包暂停发放");
            //Thread.Sleep(1000);
            Thread.CurrentThread.Abort();

          }
          Console.WriteLine("还剩{0}个红包", count);
        }
      }
      catch (ThreadAbortException ex)
      {
        // ThreadAbortException要在Exception的前面,因为Exception能够匹配所有异常
        Console.WriteLine("Method1 ThreadAbortException: " + ex.ToString());
      }
      finally
      {
        Console.WriteLine("执行完毕!");
      }

    }
  }
}

 

posted @ 2021-07-05 12:28  来自金沙江的小鱼  阅读(279)  评论(0编辑  收藏  举报