多线程编程学习笔记-基础(二)
接上文 多线程编程学习笔记-基础(一)
五、终止线程 (Abort)
1.代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入线程 namespace ThreadConsoleApp { class Program { static void Main(string[] args) { Console.WriteLine("开始"); Thread t = new Thread(PrintNumberDely); //启动线程 t.Start(); Thread.Sleep(TimeSpan.FromSeconds(6)); //线程终止 t.Abort(); Console.WriteLine("线程终止"); Console.WriteLine("启动新线程"); t = new Thread(PrintNumber); t.Start(); PrintNumber(); Console.Read(); } static void PrintNumber() { Console.WriteLine("第四个多线程程序开始。。。。Second:" + DateTime.Now.Second); for (int i = 0; i <10; i++) { Console.WriteLine(string.Format("{0}",i)); } } /// <summary> /// 暂停2秒的方法 /// </summary> static void PrintNumberDely() { Console.WriteLine("第一个多线程终止程序开始。。。。"); for (int i = 0; i < 10; i++) { Console.WriteLine(string.Format("Second:{0} == {1}", DateTime.Now.Second, i)); Thread.Sleep(TimeSpan.FromSeconds(2)); } } } }
2.程序执行结果如下
从结果中,可以看出来,程序先启动了子线程的打印数字方法,在运行了6秒之后,调用了abort方法,终止了子线程。但是这个abort是通过注入ThreadAbortException方法,从而使用线程终止,这种方法非常危险,不建议使用。在子线程终止之后,主线程继续运行。
六、检测线程状态(ThreadState)
1.代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入线程 namespace ThreadConsoleApp { class Program { static void Main(string[] args) { Console.WriteLine("开始"); Thread t = new Thread(PrintNumberStatus); Thread t2 = new Thread(DoNothing); //启动线程 t2.Start(); t.Start(); //显示线程状态 for (int i = 0; i < 10; i++) { Thread.Sleep(TimeSpan.FromMilliseconds(300)); Console.WriteLine(t.ThreadState.ToString()); } Thread.Sleep(TimeSpan.FromSeconds(4)); //线程终止 t.Abort(); Console.WriteLine("线程终止"); Console.WriteLine(string.Format("t线程状态:{0}", t.ThreadState.ToString())); Console.WriteLine(string.Format("t2线程状态:{0}", t2.ThreadState.ToString())); Console.Read(); } static void DoNothing() { Console.WriteLine("第五个多线程程序开始。。。。Second:" + DateTime.Now.Second); Thread.Sleep(TimeSpan.FromSeconds(2)); } /// <summary> /// 暂停2秒的方法 /// </summary> static void PrintNumberStatus() { Console.WriteLine("第五个多线程检测状态程序开始。。。。" + Thread.CurrentThread.ThreadState.ToString()); for (int i = 0; i < 10; i++) { Console.WriteLine(string.Format("Second:{0} == {1}", DateTime.Now.Second, i)); Thread.Sleep(TimeSpan.FromSeconds(2)); } } } }
2.程序执行结果如下
如上图,主线程启动时定义了两个子线程,一个会被终止,另一个会运行至结束。当我们启动了线程之后,t2线程的状态就会变成Running,然后会变成WaitSleepJoin,直到运行结束,变成Stopped。另一个t线程则会打印出数字来,当我们调用了abort方法之后,则t线程的状态就变成了AbortRequested。这充分说明了同步两个线程的复杂性,请不要程序中使用abort来终止线程。
七、线程优先级(Priority)
1.代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入线程 using System.Diagnostics; namespace ThreadConsoleApp { class Program { static void Main(string[] args) { Console.WriteLine("开始,当前线程的优先级:"+Thread.CurrentThread.Priority); Console.WriteLine("线程运行多核CPU上"); //启动线程 Run(); Thread.Sleep(TimeSpan.FromSeconds(2)); //单核模拟 Console.WriteLine("线程运行单核CPU上"); Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1); Run(); Console.Read(); } static void Run() { var demo = new ThreadRunDemo(); Thread thread1 = new Thread(demo.CountNumber); thread1.Name = "ThreadOne"; Thread thread2 = new Thread(demo.CountNumber); thread2.Name = "ThreadTwo"; thread2.Priority = ThreadPriority.BelowNormal; Thread thread3 = new Thread(demo.CountNumber); thread3.Name = "ThreadThree"; thread1.Priority = ThreadPriority.Highest; thread2.Priority = ThreadPriority.AboveNormal; thread3.Priority = ThreadPriority.Lowest; thread1.Start(); thread2.Start(); thread3.Start(); Thread.Sleep(2000); demo.Stop(); } } class ThreadRunDemo { private bool isStopped = false; public void Stop() { isStopped = true; } public void CountNumber() { long cnt = 0; while(!isStopped) { cnt++; } Console.WriteLine(string.Format("线程 {0} 的优先级 {1,11} ,一共计算了 {2,13} 数字",
Thread.CurrentThread.Name,Thread.CurrentThread.Priority.ToString(), cnt.ToString("N0"))); } } }
2.程序执行结果如下
从上图的结果中,看出来当在多核CPU上运行多线程程序时,优先级所起到的作用区别不大,以上图的结果来看,最高优先级与最低优先级之间的差别在10%左右。如果在单核CPU上运行多线程程序时,优先级的作用的特别明显,以上图的结果来看,最高优先级与最低优先级之间的差别在100倍以上。
八、前台线程与后台线程
1.代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //引入线程 using System.Diagnostics; namespace ThreadConsoleApp { class Program { static void Main(string[] args) { Console.WriteLine("开始,前台线程与后台线程"); var fore = new ThreadBackground(10); var back = new ThreadBackground(20); Thread threadF = new Thread(fore.CountNumber); threadF.Name = "前台线程"; Thread threadB = new Thread(back.CountNumber); threadB.Name = "后台线程"; threadB.IsBackground = true; //启动线程 threadF.Start(); threadB.Start(); //Console.Read(); } } class ThreadBackground { private int cnt ; public ThreadBackground(int count) { cnt = count; } public void CountNumber() { for (int i = 0; i < cnt; i++) { Thread.Sleep(500); Console.WriteLine(string.Format("线程 {0} 打印 {1,11} 数字", Thread.CurrentThread.Name, i.ToString("N0"))); } Console.WriteLine("{0} finished counting.", Thread.CurrentThread.IsBackground ? "Background Thread" : "Foreground Thread"); } } }
2.程序执行结果
根据上面的代码,当程序执行到如上图时,会一闪而过,退出。这是因为前台线程已经执行结束,虽然后台线程没有执行结束,但程序会自动终止后台线程。这就是前台线程与后台线程的区别,进程会等所有的前台线程执行完毕,如果此时只剩下后台线程没有执行完毕,则会直接结束工作。