线程
需要掌握的有:
1,线程的概念
2,线程的调度
3,线程也分前后台
4,线程的容器,线程池
5,线程同步
===============================================================================================
一:进程的概念: 进程是一个可执行程序,由虚拟空间地址,数据,代码,其他操作系统资源组成,一个应用程序可以有一个或多个进程.
线程的概念:线程是进程的独立执行单元,是CPU调度和分派的基本单位,一个进程可以有一个或多个线程,其中一个线程是主线程
================================================================================================
二:基于Windows是抢占式多线程操作系统,线程会在任意时间里被抢占,来调度另一个线程
class Program { static void Main(string[] args) { Console.WriteLine("主线程开始执行"); Thread t1 = new Thread(new ThreadStart(Work1)); Thread t2 = new Thread(new ThreadStart(Work1)); t1.Start(); t2.Start(); Console.WriteLine("主线程执行结束"); } public static void Work1() { while(true) { Thread.Sleep(100); Console.WriteLine("线程ID = {0}在执行",Thread.CurrentThread.ManagedThreadId.ToString()); } } public static void Work2() { while(true) { Thread.Sleep(100); Console.WriteLine("线程ID = {0}在执行",Thread.CurrentThread.ManagedThreadId.ToString()); } } }
对于线程调度的问题,我们可以通过设置线程的优先级,来让指定的线程优先执行
通过设置Priority属性来设置,有5个优先级,
ThreadPriority.xxx 这是个枚举,F12进去能看到顺序,从0到4,优先级依次递增
===============================================================================================
三:Thread 类创建的线程,默认是前台线程,主线程是前台线程,并且所有的前台线程执行完毕,后台线程就会被CLR强制结束,并且不会抛出异常,如下代码所以,
后台线程并没有被执行,因为前台线程已经结束
有三种方法可以让后台线程执行完
1:让前台线程Thread.Sleep();
2,把后台线程变成前台线程,通过IsBackgroud属性来设置
3,通过join()方法,让后台线程先执行完毕
1 static void Main(string[] args) 2 { 3 Console.WriteLine("主线程开始,ID={0}",Thread.CurrentThread.ManagedThreadId.ToString()); 4 5 Thread td = new Thread(new ThreadStart(Work)); 6 td.IsBackground = true; 7 td.Start(); 8 Console.WriteLine("主线程结束,ID={0}", Thread.CurrentThread.ManagedThreadId.ToString()); 9 } 10 11 public static void Work() 12 { 13 Console.WriteLine("后台线程开始,ID={0}",Thread.CurrentThread.ManagedThreadId.ToString()); 14 for (int i = 0; i < 10;i++ ) 15 { 16 Console.WriteLine("后台线程在工作,ID={0}",Thread.CurrentThread.ManagedThreadId.ToString()); 17 } 18 Console.WriteLine("后台工作线程结束,ID={0}",Thread.CurrentThread.ManagedThreadId.ToString()); 19 }
四 :线程池
通过手动创建线程,在销毁和创建的过程中会占用一定的资源,造成性能的损失,这个时候我们可以用线程池
线程池可以理解为线程的集合,当有任务要执行时,会通过 QueueUserWorkItem(WaitCallback callBack);将任务添加到请求消息队列中,线程池实现的代码会从消息队列中
提取任务,并委派给线程池中的线程去执行,执行完毕后,线程会被释放,但是不会被销毁,释放后等待下次任务的执行,如果线程池的线程不够使用就会创建新的线程,去执行任务
线程池的线程为后台线程,并且优先级默认为Normal
1 class Program 2 { 3 4 static void Main(string[] args) 5 { 6 Console.WriteLine("主线程开始"); 7 ThreadPool.QueueUserWorkItem(Work); 8 ThreadPool.QueueUserWorkItem(Work,"hello"); 9 Thread.Sleep(3000); 10 Console.WriteLine("主线程结束"); 11 } 12 13 public static void Work(Object o) 14 { 15 Console.WriteLine("工作线程开始"); 16 if (o == null) 17 { 18 Console.WriteLine("工作线程 ID={0}",Thread.CurrentThread.ManagedThreadId.ToString()); 19 } 20 else 21 { 22 Console.WriteLine("工作线程ID = {0},参数为{1}",Thread.CurrentThread.ManagedThreadId.ToString(),o.ToString()); 23 24 } 25 26 } 27 28 29 30 31 32 }
取消线程池线程,CancellationTokenSource的 Cancel()方法可以取消线程池的线程,取消后,CancellationToke 的IsCancellationRequested的属性为true
1 class Program 2 { 3 4 static void Main(string[] args) 5 { 6 Console.WriteLine("主线程开始"); 7 CancellationTokenSource cts = new CancellationTokenSource(); 8 ThreadPool.QueueUserWorkItem(Work,cts.Token); 9 Console.WriteLine("按回车取消"); 10 Console.ReadKey(); 11 cts.Cancel(); 12 Console.ReadKey(); 13 Console.WriteLine("主线程结束"); 14 } 15 16 public static void Work(Object o) 17 { 18 CancellationToken token = (CancellationToken)o; 19 for (int i = 0; i < 100;i++ ) 20 { 21 Thread.Sleep(300); 22 Console.WriteLine(i); 23 if(token.IsCancellationRequested) 24 { 25 Console.WriteLine("计数取消"); 26 return; 27 } 28 29 } 30 31 } 32 33 34 35 36 37 }
五,多个线程共同操作同一个资源,为了保证不损坏资源的数据,确保某一时刻只有一个线程在操作共享资源
1 class Program 2 { 3 public static int tickets = 100; 4 static void Main(string[] args) 5 { 6 Console.WriteLine("主线程开始"); 7 ThreadPool.QueueUserWorkItem(MaiPiao1); 8 ThreadPool.QueueUserWorkItem(MaiPiao2); 9 Thread.Sleep(20000); 10 Console.WriteLine("主线程结束"); 11 } 12 13 public static void MaiPiao1(object o) 14 { 15 while(true) 16 { 17 Thread.Sleep(300); 18 Console.WriteLine("窗口1----剩余票{0}",tickets); 19 tickets--; 20 if (tickets <= 0) break; 21 } 22 } 23 24 public static void MaiPiao2(object o) 25 { 26 while (true) 27 { 28 Thread.Sleep(300); 29 Console.WriteLine("窗口2----剩余票{0}", tickets); 30 tickets--; 31 if (tickets <= 0) break; 32 } 33 } 34 35 36 }
上面的代码证实了,多线程在操作共同的资源的时候,会造成资源数据的损坏
此时可以通过使用Monitor来实现线程同步
1 public static void MaiPiao1(object o) 2 { 3 while(true) 4 { 5 try 6 { 7 Thread.Sleep(300); 8 Monitor.Enter(mykey); 9 Console.WriteLine("窗口1----剩余票{0}", tickets); 10 tickets--; 11 if (tickets <= 0) break; 12 } 13 finally 14 { 15 Monitor.Exit(mykey); 16 } 17 18 } 19 }
关于死锁,线程1和线程2都使用同一个锁,线程1没有释放锁,那么线程1和线程2都处于等待状态