【实例 1】使用 ThreadStart 委托创建线程,并定义一个方法输出 0〜10 中所有的偶数。
class Program
{
static void Main(string[] args)
{
//使用 ThreadStart 创建线程首先需要创建 ThreadStart 委托的实例,然后再创建 Thread 类的实例。
ThreadStart ts = new ThreadStart(PrintEven);
Thread t = new Thread(ts);
t.Start();
}
//定义打印0~10中的偶数的方法
private static void PrintEven()
{
for (int i = 0; i < 10; i=i+2)
{
Console.WriteLine(i);
}
}
}
从上面的运行效果可以看出,使用 Threadstart 委托为 PrintEven 方法创建了线程,通过线程的 Start 方法启动线程并调用了 PrintEven 方法。
【实例 2】在上一实例的基础上添加一个打印 1〜10 中的奇数的方法,再分别使用两个 Thread 类的实例启动打印奇数和偶数的方法。
class Program
{
static void Main(string[] args)
{
ThreadStart ts1 = new ThreadStart(PrintEven);
Thread t1 = new Thread(ts1);
t1.Start();
ThreadStart ts2 = new ThreadStart(PrintOdd);
Thread t2 = new Thread(ts2);
t2.Start();
}
//定义打印0~10中的偶数的方法
private static void PrintEven()
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(i);
}
}
//定义打印1~10 中的奇数的方法
public static void PrintOdd()
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(i);
}
}
}
上述打印的并不是按照线程的调用顺序先打印出所有的偶数再打印奇数;需要注意的是,由于没有对线程的执行顺序和操作做控制,所以运行该程序每次打印的值的顺序是不一样的。
【实例 3】创建一个方法输出0〜n的所有偶数,使用 ParameterizedThreadStart 委托调用该方法,并启动打印偶数的线程。
class Program
{
static void Main(string[] args)
{
ParameterizedThreadStart pts = new ParameterizedThreadStart(PrintEven);
Thread t = new Thread(pts);
t.Start(20);
}
//打印0~n中的偶数
private static void PrintEven(Object n)
{
for (int i = 0; i <= (int)n; i = i + 2)
{
Console.WriteLine(i);
}
}
}
在使用 ParameterizedThreadStart 委托调用带参数的方法时,方法中的参数只能是 object 类型并且只能含有一个参数。在启动线程时要在线程的 Start() 方法中为委托的方法传递参数。
【实例 4】创建一个方法输出指定范围内数值的偶数,并创建线程调用该方法。
class Program
{
static void Main(string[] args)
{
ParameterizedThreadStart pts = new ParameterizedThreadStart(PrintEven);
Thread t=new Thread(pts);
//实例化对象
ParameterTest pt = new ParameterTest(6, 20);
t.Start(pt);
}
private static void PrintEven(object n)
{
//判断n是否为ParameterTest 类的对象
if(n is ParameterTest)
{
int beginNum = ((ParameterTest)n).beginNum;
int endNum= ((ParameterTest)n).endNum;
for (int i=beginNum; i<endNum; i++)
{
if(i%2==0)
{
Console.WriteLine(i);
}
}
}
}
public class ParameterTest
{
public int beginNum;
public int endNum;
public ParameterTest(int a,int b)
{
this.beginNum = a;
this.endNum = b;
}
}
}
运行该程序,在控制台上将输出 1〜20 的偶数,即2、4、6、8、10、12、14、16、18、20。
从代码可以看出,通过为 ParameterTest 类中的字段赋值,并将其通过线程的 Start 方法传递给委托引用的方法 PrintEven,即可实现在委托引用的方法中传递多个参数的操作。
【实例 5】通过设置线程的优先级来控制输出奇数和偶数的线程,为了看出设置线程优先级的效果将输出 1〜100 中的奇数和 0〜100 中的偶数。
class Program
{
static void Main(string[] args)
{
ThreadStart ts1 = new ThreadStart(PrintEven);
Thread t1 = new Thread(ts1);
//设置打印偶数线程的优先级
t1.Priority = ThreadPriority.Lowest;
ThreadStart ts2 = new ThreadStart(PrintOdd);
Thread t2 = new Thread(ts2);
//设置打印奇数线程的优先级
t2.Priority = ThreadPriority.Highest;
t1.Start();
t2.Start();
}
//打印1~100中的奇数
public static void PrintOdd()
{
for (int i = 1; i <= 20; i = i + 2)
{
Console.WriteLine(i);
}
}
//打印0~100中的偶数
public static void PrintEven()
{
for (int i = 0; i <= 20; i = i + 2)
{
Console.WriteLine(i);
}
}
}
在 C# 中线程的优先级使用线程的 Priority 属性设置即可,默认的优先级是 Normal。
在设置优先级后,优先级高的线程将优先执行。
优先级的值通过 ThreadPriority 枚举类型来设置,从低到高分别为Lowest、BelowNormal、Normal、AboveNormal、Highest。
从上面的运行效果可以看出,由于输岀奇数的线程的优先级高于输出偶数的线程,所以在输出结果中优先输出奇数的次数会更多。
此外,每次输出的结果也不是固定的。通过优先级是不能控制线程中的先后执行顺序的,只能是优先级高的线程优先执行的次数多而已
【实例 6】使用暂停线程(Sleep) 的方法让打印奇数和打印偶数的线程交替执行,即打印 0〜10 的数。
class Program
{
static void Main(string[] args)
{
ThreadStart ts1 = new ThreadStart(PrintOdd);
Thread t1 = new Thread(ts1);
ThreadStart ts2 = new ThreadStart(PrintEven);
Thread t2 = new Thread(ts2);
t1.Start();
t2.Start();
}
//打印1~100中的奇数
public static void PrintOdd()
{
for (int i = 1; i <= 10; i = i + 2)
{
//让线程休眠 1 秒
Thread.Sleep(1000);
Console.WriteLine(i);
}
}
//打印0~100中的偶数
public static void PrintEven()
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(i);
//让线程休眠 1 秒
Thread.Sleep(1000);
}
}
}
从上面的运行效果可以看出,通过 Sleep 方法能控制两个线程执行的先后顺序。
需要注意的是,两个线程虽然交替执行,但每次运行该程序的效果依然是不同的。
【实例 7】模拟发放 10 个红包,当剩余 5 个红包时线程终止。
class Program
{
public static int count = 10;
private static void GiveRedEnvelop()
{
while(count>0)
{
count--;
if(count==4)
{
//终止当前线程
Console.WriteLine("红包暂停发放!");
Thread.CurrentThread.Abort();
}
Console.WriteLine("剩余{0}个红包",count);
}
}
static void Main(string[] args)
{
ThreadStart ts = new ThreadStart(GiveRedEnvelop);
Thread t = new Thread(ts);
t.Start();
}
}
线程分为前台线程和后台线程,前台线程不用等主程序结束,后台线程则需要应用程序运行结束后才能结束。
此外,在应用程序运行结束后,后台线程即使没有运行完也会结束,前台线程必须等待自身线程运行结束后才会结束。
【实例 8】在上一实例的基础上判断发红包的线程是否为后台线程,如果不是后台线程,将其设置为后台线程。
class Program
{
public static int count = 10;
private static void GiveRedEnvelop()
{
while (count > 0)
{
count--;
if (count == 4)
{
//终止当前线程
Console.WriteLine("红包暂停发放!");
Thread.CurrentThread.Abort();
}
Console.WriteLine("剩余{0}个红包", count);
}
}
static void Main(string[] args)
{
ThreadStart ts = new ThreadStart(GiveRedEnvelop);
Thread t = new Thread(ts);
t.Start();
if(t.IsBackground==false)
{
Console.WriteLine("该线程不是后台线程!");
t.IsBackground = true;
}
else
{
Console.WriteLine("该线程是后台线程!");
}
}
}
运行该程序,直接输出“该线程不是后台线程!”,由于将该线程设置为后台线程,则不会输出红包发放的信息。