在学习ThreadStart时,做过2个线程的练习-输出奇数和偶数,每次结果不一样,说明这两个线程随机的交替进行。如果希望控制输出顺序,就要定义优先级。
在 C# 中线程的优先级使用线程的 Priority 属性设置即可,默认的优先级是 Normal。
在设置优先级后,优先级高的线程将优先执行。但不能说优先级高的执行完毕才执行优先级低的。
优先级的值通过 ThreadPriority 枚举类型来设置,从低到高分别为Lowest、BelowNormal、Normal、AboveNormal、Highest。
对前一个练习做一下修改,设置每一个线程的优先级,控制执行顺序。
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("执行完毕!");
} }
}
}