手机版

net面向对象多线程和多线程高级应用程序

时间:2021-09-09 来源:互联网 编辑:宝哥软件园 浏览:

中线程资源共享中线程安全和线程冲突的解决方案。net面向对象编程阶段;多线程同步,利用线程锁和线程通知实现线程同步,具体内容介绍如下:

1.线程静态特性

属性:[线程静态]

函数:指定静态字段在不同的线程中有不同的值

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

我们定义一个静态字段:

静态int num=0;然后创建两个线程分别进行累积:

新线程(()={ for(int I=0;我1000000;数量;控制台。WriteLine('来自{0} : {1} ',thread.currentthread.name,num);}){ Name=' thread one' }。start();新线程(()={ for(int I=0;i 2000000数量;控制台。WriteLine('来自{0} : {1} ',thread.currentthread.name,num);}){名称='线程二' }。start();多次运行的结果如下:

可以看出,三次运行的结果是不同的,造成这个问题的原因是多线程中的同步共享问题,即多个线程同时共享一个资源。解决上述问题的最简单方法是使用静态字段的ThreadStatic特性。

定义静态字段时,按如下方式添加[ThreadStatic]属性:

复制代码如下:【线程静态】static int num=0;在两个线程不变的情况下,再次运行,结果如下:

不管跑多少次,结果都是一样的。当该字段被Threadstatic修改时,它的值在每个线程中是不同的,也就是说,每个线程都会将内存空间重新分配给静态字段,这当然是一个新的操作,这样就消除了静态字段带来的问题。

2.资源共享

多线程资源共享就是多线程同步。需要注意的是,线程同步是指线程访问资源的同步,而不是线程本身的同步。

在多线程的实际使用中,并不是所有的线程都访问不同的资源。

让我们看一个线程示例。如果我们不知道线程需要多长时间才能完成,我们会等待一个固定的时间(如果是500毫秒):

首先定义一个静态字段:

静态int结果;创建线程:

线程神话读取=新线程(()={线程。睡眠(1000);结果=100;});神话阅读。start();线程。睡眠(500);控制台。WriteLine(结果);运行结果如下:

我们可以看到结果是0,这显然不是我们想要的,但是我们经常不知道线程执行时需要多长时间才能完成。线程完成后,我们可以有通知吗?

这里有很多愚蠢的方法,比如我们可能会想到用一个循环来检测线程状态,这并不理想。NET为我们提供了一种Join方法,即线程阻塞,可以解决上述问题。我们用秒表来计时。

改进的线程代码如下:

系统。诊断。秒表手表=系统。诊断.秒表. startnew();线程神话读取=新线程(()={线程。睡眠(1000);结果=100;});神话阅读。start();线程。睡眠(500);神话阅读。join();控制台。WriteLine(观察。elapsedmirisseconds);控制台。WriteLine(结果);运行结果如下:

结果和我们想要的一致。

3.螺纹锁

除了上述示例中的方法之外。NET还为我们提供了一种锁定机制来解决线程同步的同步问题。上面的例子改进如下:

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

静态对象锁定器=新对象();在这里,我们不必考虑这个对象是什么。继续看改进的线程:

系统。诊断。秒表手表=系统。诊断.秒表. startnew();线程t1=新线程(()={锁(锁){线程。睡眠(1000);结果=100;}});t1。start();线程。睡眠(100);锁(储物柜){控制台。WriteLine('线程时间:' watch。elapsedmirisseconds);控制台。WriteLine('线程输出:' result ');}运行结果如下:

运行结果与上面的例子相同。如果线程处理过程比较复杂,可以看出时间消耗明显减少,这是一种比阻塞更高效的完成线程同步的方式。

4.线程通知

我们讨论了在线程完成后是否可以通知等待的线程。给你。NET为我们提供了一种事件通知方法来解决这个问题。

4.1自动设置事件

首先定义通知对象

复制代码如下: static eventwaithandle告诉我=new autore setevent(false);对上述思路进行如下改进:

系统。诊断。秒表手表=系统。诊断.秒表. startnew();线程神话读取=新线程(()={线程。睡眠(1000);结果=100;告诉我。set();});神话阅读。start();告诉我。wait one();控制台。WriteLine('线程时间:' watch。elapsedmirisseconds);控制台。WriteLine('线程输出:' result ');运行结果如下:

4.2手动重置事件

与自动设置事件相比,还有手动设置事件手动模式。它们之间的区别在于,除非关闭手动重置,否则手动重置事件在线程结束后仍然可以通过。让我们看一个例子:

首先,为手动通知定义一个对象:

static EventWaitHandle MRE=new ManualResetEvent(false);创建线程:

系统。诊断。秒表手表=系统。诊断.秒表. startnew();线程myThreadFirst=新线程(()={ Thread。睡眠(1000);结果=100;mre。set();}){ Name=' thread one ' };Thread myThreadSecond=new Thread(()={ MRE。wait one();console . write line(thread . currentthread . name)获取结果:“result”()system。datetime . now . tostring()“)”);}){ Name=' thread two ' };首先是神话。start();第二个神话。start();mre。wait one();控制台。WriteLine('线程时间:' watch .流逝的毫秒'(' system . datetime . now . tostring()')));控制台。WriteLine('线程输出:' result '('系统。datetime . now . tostring()“)”);运行结果如下:

4.3.旗语

信号量也是一种线程通知。在上面的通知模式中,当打开大量线程时,如果使用Reset()关闭,而不使用Sleep,那么如果某些线程没有恢复,很有可能某个线程会提前关闭。对于这种不可预测的情况,NET提供了更高级的通知模式,可以保证多线程中不会出现上述问题。

首先,定义通知对象的静态字段:

复制代码如下:静态信号量SEM=新信号量(2,2);使用一个循环创建100个线程:

for(int I=1;i=100i ){新线程(()={ sem。wait one();线程。睡眠(30);控制台。写线(线程。名称为“”的日期时间。now . ToString());扫描电镜。release();}) {Name=' thread' i}。start();}运行结果如下:

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

5.本节的要点:

A.线程中静态字段的ThreadStatic属性,在不同的线程中有不同的值

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

C.线程通知的两种方式:autosetevent/manualreseteevent和Semaphore

到此为止,介绍到此结束。net面向对象多线程和多线程高级应用程序。

版权声明:net面向对象多线程和多线程高级应用程序是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。