星空网 > 软件开发 > ASP.net

[.net 面向对象程序设计进阶] 多线程(Multithreading)(二) 多线程高级应用(上)

[.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 多线程高级应用(上)

本节要点: 

上节介绍了多线程的基本使用方法和基本应用示例,本节深入介绍.NET多线程中的高级应用。

主要有在线程资源共享中的线程安全和线程冲突的解决方案;多线程同步,使用线程锁和线程通知实现线程同步。

1、 ThreadStatic特性 

特性:[ThreadStatic] 

功能:指定静态字段在不同线程中拥有不同的值 

在此之前,我们先看一个多线程的示例: 

我们定义一个静态字段: 

 static int num = 0;

 然后创建两个线程进行分别累加: 

new Thread(() =>{  for (int i = 0; i < 1000000; i++)    ++num;  Console.WriteLine("来自{0}:{1}", Thread.CurrentThread.Name, num);}){ Name = "线程一" }.Start();  

new Thread(() =>{  for (int i = 0; i < 2000000; i++)    ++num;  Console.WriteLine("来自{0}:{1}", Thread.CurrentThread.Name, num);}){ Name = "线程二" }.Start();

运行多次结果如下: 

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)  [.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)  [.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上) 

可以看到,三次的运行结果均不相同,产生这种问题的原因是多线程中同步共享问题导致的,即是多个线程同时共享了一个资源。如何解决上述问题,最简单的方法就是使用静态字段的ThreadStatic特性。 

在定义静态字段时,加上[ThreadStatic]特性,如下: 

 [ThreadStatic]static int num = 0; 

两个线程不变的情况下,再次运行,结果如下: 

 [.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上) 

不论运行多少次,结果都是一样的,当字段被ThreadStatic特性修饰后,它的值在每个线程中都是不同的,即每个线程对static字段都会重新分配内存空间,就当然于一次new操作,这样一来,由于static字段所产生的问题也就没有了。

2. 资源共享 

多线程的资源共享,也就是多线程同步(即资源同步),需要注意的是线程同步指的是线程所访问的资源同步,并非是线程本身的同步。 

在实际使用多线程的过程中,并非都是各个线程访问不同的资源。 

下面看一个线程示例,假如我们并不知道线程要多久完成,我们等待一个固定的时间(假如是500毫秒):

先定义一个静态字段:

 static int result;

创建线程:

Thread myThread = new Thread(() =>{  Thread.Sleep(1000);  result = 100;});myThread.Start();Thread.Sleep(500);       Console.WriteLine(result);

运行结果如下:

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上) 

可以看到结果是0,显然不是我们想要的,但往往在线程执行过程中,我们并不知道它要多久完成,能不能在线程完成后有一个通知?

这里有很多笨的方法,比如我们可能会想到使用一个循环来检测线程状态,这些都不是理想的。

.NET为我们提供了一个Join方法,就是线程阻塞,可以解决上述问题,我们使用Stopwatch来记时,

改进线程代码如下:

System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();Thread myThread = new Thread(() =>{  Thread.Sleep(1000);  result = 100;});myThread.Start();Thread.Sleep(500);myThread.Join();Console.WriteLine(watch.ElapsedMilliseconds);Console.WriteLine(result);

运行结果如下:

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)

 结果和我们想要的是一致的。

3. 线程锁

除了上面示例的方法,对于线程同步,.NET还为我们提供了一个锁机制来解决同步,再次改进上面示例如下:

先定义一个静态字段来存储锁:

static object locker = new object();

这里我们可以先不用考虑这个对象是什么。继续看改进后的线程:

System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();Thread t1 = new Thread(() =>{  lock (locker)  {    Thread.Sleep(1000);    result = 100;  }});t1.Start();Thread.Sleep(100);lock (locker){  Console.WriteLine("线程耗时:"+watch.ElapsedMilliseconds);  Console.WriteLine("线程输出:"+result);}

运行结果如下:

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)

运行结果和上面示例一样,如果线程处理过程较复杂,可以看到耗时明显减少,这是一种用比阻塞更效率的方式完成线程同步。

4. 线程通知

前面说到了能否在一个线程完成后,通知等待的线程呢,这里.NET为我们提供了一个事件通知的方法来解决这个问题。 

4.1 AutoResetEvent  

先定义一个通知对象

 static EventWaitHandle tellMe = new AutoResetEvent(false);

改进上面的线程如下: 

System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();Thread myThread = new Thread(() =>{  Thread.Sleep(1000);  result = 100;  tellMe.Set();});myThread.Start();tellMe.WaitOne();Console.WriteLine("线程耗时:" + watch.ElapsedMilliseconds);Console.WriteLine("线程输出:" + result);

 运行结果如下:

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)

4.2 ManualResetEvent 

和AutoResetEvent 相对的还有一个 ManualResetEvent 手动模式,他们的区别在于,在线程结束后ManualResetEvent 还是可以通行的,除非手动Reset关闭。下面看一个示例:

先定义一个手动通知的对象:

 static EventWaitHandle mre = new ManualResetEvent(false);

创建线程:

System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();Thread myThreadFirst = new Thread(() =>{  Thread.Sleep(1000);  result = 100;  mre.Set();}) { Name = "线程一" };Thread myThreadSecond = new Thread(() =>{  mre.WaitOne();  Console.WriteLine(Thread.CurrentThread.Name + "获取结果:" + result + "("+System.DateTime.Now.ToString()+")");}) { Name="线程二"};myThreadFirst.Start();myThreadSecond.Start();mre.WaitOne();Console.WriteLine("线程耗时:" + watch.ElapsedMilliseconds + "(" + System.DateTime.Now.ToString() + ")");Console.WriteLine("线程输出:" + result + "(" + System.DateTime.Now.ToString() + ")");

运行结果如下:

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)

5. Semaphore

Semaphore也是一种锁定,只不过不是独占锁,可以指定多少个线程访问代码块。上面的通知模式,在线程开启的数量很多的情况下,使用Reset()关闭时,如果不使用Sleep休眠一下,很有可能导致某些线程没有恢复的情况下,某一线程提前关闭,对于这种很难预测的情况,.NET提供了更高级的通知方式Semaphore,可以保证在超多线程时不会出现上述问题。

先定义一个通知对象的静态字段:

 static Semaphore sem = new Semaphore(2, 2);

使用循环创建100个线程:

for (int i = 1; i <= 100; i++){  new Thread(() =>  {    sem.WaitOne();    Thread.Sleep(30);    Console.WriteLine(Thread.CurrentThread.Name+"  "+DateTime.Now.ToString());    sem.Release();  }) { Name="线程"+i}.Start();}

运行结果如下:

[.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上) 

可以看到完整的输出我们所想要看到的结果。

6. 本节要点:

A.线程中静态字段的ThreadStatic特性,使用该字段在不同线程中拥有不同的值

B.线程同步的几种方式,线程锁和线程通知

C.线程通知的两种方式:AutoResetEvent /ManualResetEvent  

D.Semaphore:不独占锁,可以指定多少个线程访问代码块。

多线程的更多特性,下一节继续深入介绍。

==============================================================================================

返回目录

<如果对你有帮助,记得点一下推荐哦,如有有不明白或错误之处,请多交流>

<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>

<转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>

.NET 技术交流群:467189533 [.net 面向对象程序设计进阶]  多线程(Multithreading)(二) 多线程高级应用(上)

==============================================================================================




原标题:[.net 面向对象程序设计进阶] 多线程(Multithreading)(二) 多线程高级应用(上)

关键词:.NET

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

获取你的vat number:简单、快捷、有效:https://www.kjdsnews.com/a/1322080.html
回答:在阿联酋开站:注册是否需要申请vat:https://www.kjdsnews.com/a/1322081.html
荷兰vat站点: 全面了解荷兰增值税缴纳流程:https://www.kjdsnews.com/a/1322082.html
荷兰vat税率:6%及21%的最新情况:https://www.kjdsnews.com/a/1322083.html
关于vat和关税的不同之处:思考更深层次的差异:https://www.kjdsnews.com/a/1322084.html
菲律宾:如何应用vat以最佳利益达到财务目标:https://www.kjdsnews.com/a/1322085.html
马来西亚加强BNPL业务监管,Shopee等服务供应商被点名!:https://www.kjdsnews.com/a/1842255.html
马来西亚加强BNPL业务监管,Shopee等服务供应商被点名!:https://www.goluckyvip.com/news/220218.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流