这里我要强调一个概念,
多线程是多线程,
异步编程是异步编程
这两个是有区别的概念;
我可以说多线程天生就要异步的特点;但你不能说多线程成就等同于我们的异步编程;
根不能说异步编程就是我们的多线程。这里不要搞混淆了;
再net中的进化如下:
多线程:Thread =>ThreadPool=> Task
异步编程:BenginInvokeXXX EndInvokeXXX IAsyncResult=> async await (这里面配合着Task的使用)。
好接下来,再来总结我们的线程(任务)的等待。
总结:
方法一:Thread.Sleep(),这个要预估,等待的时间应该大于我们的子线程执行的时间。
方法二:当然就是我们最常用的Join() 方法了,堵塞当前调用子线程成的方法,直到我们的子线程执行完毕。
方法二:主线程轮训子线程(这个是基于我们的IasyncResult 编程模式的,及时传说中的beginxxxx endxxxx这种模式)
方法三:采用通知的方法就是我们的EevntWaitHanld = new AutoRestEevnt(false),然后waitOne 和 Set 的方式来进行的,效果非常好滴呀;
方法四:我把它命名为偏方:就是利用独占锁的机制,当子线程用完锁之后,释放,让给我们的主线程,前提是要确保我们的子线程先得到锁;
方法五:这个就是基于我们的Task的wait方法;
这里我给出一些,练习的demo,仅供参考使用;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication13 { //我们把它叫做等待子线程,或者,等待子线程一定的时间; //最原始的是使用 waitEevnt的方法;我们甚至可以用 poll的方式; //还有基于事件编程的回调方式; public class Person { } class Program { //evnet wait handle //该方法也可以用来进行线程的同步滴呀; public static object locker = new object(); public static EventWaitHandle handler = new AutoResetEvent(false); public static void Eat() { Thread.Sleep(3000); } public static void Eat_WithSet() { Thread.Sleep(3000); handler.Set(); //子线程发出做完实行的信号; } public static void Eat_WithLock() { Console.WriteLine("枷锁开始"); lock (locker) { Thread.Sleep(3000); //假设,我们这里有很多的是事情要做的呀; //效果非常好; } Console.WriteLine("枷锁释放"); } public static void Eat_Loop() { for (int i = 0; i < 10; i++) { Thread.Sleep(1000); Console.WriteLine("子"); } } //那么这个方法就不能为空了 public static void Eat_Wait() { for (int i = 0; i < 10; i++) { Task.Delay(1000).Wait(); Console.WriteLine("子"); } } public static void TestJoin() { Console.WriteLine("main start"); Thread thread = new Thread(Eat); thread.Start(); //给我等着; Console.WriteLine("主线程先做点其他事情;"); //这我们我们可以直接用线程自带的方法; thread.Join(); Console.WriteLine("好了,子线程事情做完了.."); Console.WriteLine("main end"); Console.ReadLine(); } public static void Test_Set() { Console.WriteLine("main start"); Thread thread = new Thread(Eat_WithSet); thread.Start(); //给我等着; Console.WriteLine("主线程先做点其他事情;"); handler.WaitOne(); Console.WriteLine("好了,子线程事情做完了.."); Console.WriteLine("main end"); Console.ReadLine(); } public static void Test11() { Console.WriteLine("main start"); Thread thread = new Thread(Eat_WithSet); thread.Start(); //给我等着; Console.WriteLine("主线程先做点其他事情;"); handler.WaitOne(TimeSpan.FromSeconds(3)); //注意这里,一点 waitone 和 task.wait 如果都指定了 等待的时间; //如果子线程在指定的时间内没有做完时间,那么我们就开始了主线程的方法; //这里并没有真正的取消线程; //问题又来了,如果去取消子线程呢;这个...... Console.WriteLine("好了,不堵塞,主线程了,"); Console.WriteLine("main end"); Console.ReadLine(); } //偏方 public static void Test_Lock() { Console.WriteLine("main start"); Thread thread = new Thread(Eat_WithLock); thread.Start(); //给我等着; Console.WriteLine("主线程先做点其他事情;"); //如果是单线层的话,我还是使用一点偏方; //那就是我们的lock方法滴呀; Thread.Sleep(20);//为了让子线程得到锁,我们这里估计sleep一下了 //所以尼玛的叫偏方了; lock (locker) { //当然这种方式,就是完全出去一种四等的状态; //等待另外一个线程释放锁; Console.WriteLine("这个表示我们的另外一个线程执行完毕了;"); } Console.ReadLine(); } //如果要取消原来的方法的话,还得到原来的的方法去操作,整的是麻烦的一件事情; //不过有我们的Task 就方便多;; public static void Test_Task() { //task的取消就相对简单的多了; Console.WriteLine("main start"); Task task = Task.Run(()=>Eat_Wait()); Console.WriteLine("mian do something.then wait task"); // task.Wait(); //默认情况下,它会等待task执行完毕; task.Wait(TimeSpan.FromSeconds(3));//在这里只能等待三秒,三秒只有,就不堵塞我们的主线程; //这里这的注意的事情是,等待不等于取消哦; //这一点是相对非常关键的啦; //先一节我们再来略略线程的取消啦滴呀; Console.WriteLine("task completed..."); Console.WriteLine("main end"); Console.ReadLine(); } static void Main(string[] args) { //Test(); //Test1(); //Test11(); //Test_Lock(); //Test_Task(); } } }
//这里我再来演示一个set 之后,通知多个线程的实例,或则理解成为广播是似的传递消息;
或则:多个线程在等待某一个线程的信号;
时间: 2024-10-20 10:02:32