async 和 await 出现在C# 5.0之后,关系是两兄弟,Task是父辈,Thread是爷爷辈,这就是.net 多线程处理的东西,具体包括 创建线程,线程结果返回,线程中止,线程中的异常处理
1 线程创建的几个方式
static void Main(string[] args) { new Thread(NewThread).Start();//这里需要注意:创建一个 new Thread()的实例的时候,需要手动调用它的Start()去启动这个实例, //对于Task来说StartNew和Run的同时,既会创建新的线程,又会自动启动这个线程 Task.Factory.StartNew(NewThread); Task.Run(new Action(NewThread)); } public static void NewThread() { Console.WriteLine("我是一个New线程!"); }
2 使用线程池
//线程的创建是比较耗费资源的一件事情,.net提供了线程池来帮助创建和管理线程,Task默认会直接使用线程池 //但是Thread不会,如果不使用Task,又想使用线程池,可以使用ThreadPool类 static void Main(string[] args) { Console.WriteLine("我是主线程:ThreadId为{0}", Thread.CurrentThread.ManagedThreadId); ThreadPool.QueueUserWorkItem(NewThread); Console.ReadKey(); } public static void NewThread(object data) { Console.WriteLine("我是一个New线程,线程Id是{0}", Thread.CurrentThread.ManagedThreadId); Console.ReadKey(); }
3 传入参数
//传入参数 static void Main(string[] args) { new Thread(NewThread).Start("arg1");//没有匿名委托之前只能这样传入一个参数 //有了匿名委托之后,可以传入多个参数 new Thread(delegate() { NewThread2("arg1", "arg2", "arg3"); }).Start(); //Lambda匿名委托 new Thread(() => { NewThread2("arg1", "arg2", "arg3"); }).Start(); } public static void NewThread() { Console.WriteLine("我是一个New线程!"); } public static void NewThread2(string arg1, string arg2, string arg3) { Console.WriteLine("我是一个New线程!"); }
4 返回值
//返回值 //Thread这玩意是没有返回值的,但是高级的Task可以 static void Main(string[] args) { var str = Task.Run<string>(() => { return DateTime.Now.ToString(); }); }
5 线程之间数据共享
//线程之间共享数据问题(这种存在问题:如果第一个线程还没来得及把_isOK设置为True,第二个线程就进来了,这样在多线程情况下,结果不可预知,这就是线程不安全) private static bool _isOK = false; static void Main(string[] args) { new Thread(DoOk).Start(); Task.Factory.StartNew(DoOk); Task.Run(() => { DoOk(); }); Task.Run(new Action(DoOk)); } static void DoOk() { if (!_isOK) { Console.WriteLine("OK"); _isOK = true; Console.ReadKey(); } }
6 独占锁
//解决上面线程不安全的问题就要用到锁(锁的类型有 读写锁,独占锁,互斥锁) //独占锁 private static bool _isOK = false; private static object _lock = new object(); static void Main(string[] args) { new Thread(DoOk).Start(); Task.Factory.StartNew(DoOk); Task.Run(() => { DoOk(); }); Task.Run(new Action(DoOk)); } static void DoOk() { lock (_lock)//独占锁,加上锁之后,被锁的代码在同一个时间内,只允许一个线性进行访问, //其他线程会被阻塞排队,只有这个线程被释放之后,其他线程才能执行被锁的代码,因为这时候,之前的线程已经访问完毕,锁已经被释放 { if (!_isOK) { Console.WriteLine("OK"); _isOK = true; Console.ReadKey(); } } }
7 线程量(信号量)
//SemaphoreSlim 可以控制对某一段代码或者对某个资源访问的线程的数量,超过这个数量其他线程就得等待,等可以访问的数量的线程访问完之后,其他线程才可以继续访问, //跟锁的原理相似,但不是独占的,可以允许一定数量的线程同时访问 static SemaphoreSlim _sem = new SemaphoreSlim(3); static void Main(string[] args) { for (int i = 1; i <= 5; i++) { //new Thread(() => //{ // Entry(i); //}).Start(); new Thread(Entry).Start(i); } } static void Entry(object id) { Console.WriteLine(id + "开始排队..."); _sem.Wait(); Console.WriteLine(id + "开始执行..."); Thread.Sleep(1000 * (int)id); Console.WriteLine(id + "执行完毕,离开"); _sem.Release(); Console.ReadKey(); }
8 捕获异常
a:
//使用Thread 线程的异常处理(其他线程的异常,主线程能捕获到么?) static void Main(string[] args) { try { new Thread(Entry).Start(); } catch (Exception ee) { //这里其他线程的异常是捕获不到的 Console.WriteLine("捕获到异常!"); } Console.ReadKey(); } static void Entry() { throw null; }
b:
static void Main(string[] args) { try { var task = Task.Run(() => { Entry(); }); task.Wait();//调用这句话之后主线程才能捕获task里面的异常 //对于有返回值的Task,接收了它的返回值就不需要再调用Wait(),Entry2()里面的异常有可以捕获到 var task2 = Task.Run(() => { return Entry2(); }); var name = task2.Result; } catch (Exception) { Console.WriteLine("捕获到异常!"); Console.ReadKey(); } } static void Entry() { throw null; } static string Entry2() { throw null; }
时间: 2024-11-02 02:17:38