接着前一篇博文的内容我们开始学习线程的同步和异步相关的内容,很多自学的新手同学可能精力的回避这个问题,其实很简单的,下面先给那些不理解这个概念的同学讲两个关于某人的故事,听完了,你就明白实战出真理的道理了(如果新手从本文中略有所获就支持一下同样是新手的偶,给我个信息知道我没耽误你的时间,当然大家可以给我点建设性的意见和指导)。

什么是线程同步?

    从前某人混社会的时候,某人第一次去江湖厮杀,结果马上就遇到了地头蛇,某人靠被砍的很惨,连掏手机打个电话的机会都不给我,这时候有两条路给某人选择,要吗掏手机命没了,要吗继续扛着结果手机没法掏出来,于是某人发挥了珍惜生命的优良传统,某人就硬是扛到最后。你现在明白我在干什么了,呵呵,这就是同步,就是说你在干一件事的时候不能去同时做别的事情,否则就会发生意外(那就是你把命掉了)。这就是线程同步的意义,假设多个线程同时访问一个资源,.NET的定义的线程优先级还要看操作系统的心情,人家爱理不理,此外就是你应该有这么一个概念:Win32线程调度程序和CLR允许线程可以自由的跨越应用程序域的边界,但是任何一个时间点上,任何应用程序域上都可以有多个线程,但是一个线程只能在一个特定的应用程序域内,也就是说一个线程在任何时刻在多个应用程序域内是不可能同时执行的。很经典的例子就是那个啥,假设你不用多线程你使用Winfrom在其中运行一个超大循环的时候,(我发挥我高超的美术功底画了个了画演示一下)(这个程序虽然简单但是涉及一个跨线程访问的问题,如果有时间就到后面的博文拿出来分析一下)。

  你再去拖动程序窗体,结果你发现你力气没window力气大,而且还吃了没文化的亏,因为这个循环的执行和你这个托这个动作都是出于同一个线程(主线程中),同时干这两件事,如果你乱来,就算拖动了,他也就崩溃了,哈哈,现在明白了吧,这就是同步。
现在我们解释什么是异步!
    经过第一次的教训出去的时候某人带了给小弟,结果还是更背,这次遇到了古惑仔,但是某人在招架的时候给小弟用嘴说你快打电话给老子搬救兵,最少三卡车,结果,某人没有自己掏电话,某人只是用特定的信息告诉小弟,某人继续干自己的事,搬救兵的事小弟就替我办了,结果这次某人没有吃亏,还是某人在小学学好了统筹学,同样的时间,办了几件事,还是小弟听话,某人自豪的笑了。多说无益,怕兄弟们烦,这就是异步操作,ajax的异步机制就是这样了,可以实现网页的局部更新等等......就不扯到asp.net上了,现在你应该明白了什么是异步了吧。


  我在这系列博文中不打算提到线程的优先级以及线程状态,这些大家就自己看吧,毕竟是次要的内容,瞄一眼就懂了。


.NET提供了两种方法可以实现同步,就是简单方法和高级方法,这就废话了,哈哈,对了据说.NET1.0还支持跨进程访问线程的,后还就给禁止掉了,不过现在还是可以通过取消跨进程访问的某个属性可以解除这种不安全的访问手段,靠又扯远了。

继续,简单方法就是轮询和等待,高级方法就是使用同步对象。

什么是轮询?

  轮询其实效率低的都没人去用它,它的原理就是循环的去侦听线程的状态,而且就算侦听到了都有可能误判,假设砸门使用IsAlive来检测某个线程是否退出的时候我们要有这么个概念处于活动状态的线程不一定是运行的,就是说他亦可能出于休眠状态。

什么又是等待?

  所谓的等待,懂汉语的孩子都知道就是等着某个对象办事情了,这个我在前面的一篇博文用到的很多,那就是Join,同样,好多小弟弟们搞不明白Join到底是啥,好多文章加了那么个调用线程#¥%……的概念就把孩子们搞晕了,看群里搞晕的小弟弟还是蛮多的,其实你管那么多干嘛,试验下不就知道了,下面由于我在前面的博文中已经大量使用Join了,这里就不演示了,最要给个通俗的解释就是那个线程执行了Join方法,那么其他的线程都必须等待到该线程执行完为止才会有反应,但是我在这里再补充一下,就是这个“执行完”也是相对的,就是在该线程的执行过程中万一有调用了Sleep()方法休眠了一下,那么别的线程管你还有没有执行完,CPU就会把时间片分给别的线程去执行他们的任务,直到这个线程再次唤醒为止。当然既然是简单问题肯定只能解决简单的逻辑,要是流程一复杂,你就找比尔盖兹的工程师给你用Join给你解决线程同步的问题吧^@^!具体的实例可以看上一篇文章。

演示并发

  说了这么久,我们干脆先演示下并发的程序,来分析下并发产生的问题,在进入下文介绍解决并发的高级方法。

先在有这么一点代码,先贴出来咱们在分析。

 1 using System;
 2 using System.Threading;
 3 public class Printer
 4 {
 5     public void PrintNumbers()
 6             {
 7
 8               for (int i = 0; i < 10; i++)
 9               {
10                 Random r = new Random();
11                 Thread.Sleep(500 * r.Next(3));
12                 Console.Write("{0}, ", i);
13               }
14               Console.WriteLine();
15             }
16     class Program
17     {
18         static void Main(string[] args)
19         {
20             Console.WriteLine("*****线程同步 *****\n");
21
22             Printer p = new Printer();
23
24             Thread[] threads = new Thread[10];
25             for (int i = 0; i < 10; i++)
26             {
27                 threads[i] =new Thread(new ThreadStart(p.PrintNumbers));
28                 threads[i].Name = string.Format("工作线程 thread #{0}启动执行!", i);
29                 Console.WriteLine(threads[i].Name);
30             }
31             foreach (Thread t in threads)
32                 t.Start();
33             Console.ReadLine();
34         }
35     }
36 }

乍一看,咋们肯定知道要是按正常的运行,肯定是每次循环输出10个数字,但是结果并非我们一厢情愿,我们运行看一下:(注:由于使用随机函数这个结果只是其中一种)

结果我们发现结果不是我们预料大的,毛呀,这是肿么了,有木有搞错啊,为什么会这样?

threads[i] =new Thread(new ThreadStart(p.PrintNumbers));

  我们来看这一句代码,我们发现每一个线程都是调用同一个对象p的PrintNumbers方法,或许这只是个线索而已,接着我们再看这句:Thread.Sleep(500 * r.Next(3));我们就会发现,这里随机挂起线程的时间不能确定 ,可能的情况就是当即将发生printNumbers方法的时候,还没等输出到控制台,当前的线程就被挂起了,win32的线程调度程序就切换线程,于是就发生了我们不可预料的结果。怎么解决了,哈哈是不是想用上面的上面的Join一下啊,完全可以有什么不可以的,咋们试试先,不过我们要引入高级方法,又要用低级方法验证一下,可不可以,我们的思路是什么呢:就是要线程调度程序等到哥执行完了当前线程再去执行下一个线程,稍加修改代码我们测试一下,我们只在这里动一下手脚:
 foreach (Thread t in threads){t.Start();t.Join();}

但是结果就立马不同了,因为我们都知道每个线程都执行完成了,结果如你所愿:


那么怎么用高级方法解决这个问题呢?

我们为了节约时间先做一个最简单lock方法,这个其实是为了方便Monitor类的使用应用而生(完全等价于Monitor类的调用形式)。具体的后期再解释,咋们先只要知道高级方法解决这些问题,还是最优的选择就行了,先有个大概影响,后续博文慢慢研究。不可能一次都写完,我还要上课,还要去看电影,呵呵....

  我们先解释下lock关键字,这个关键字允许定义一段线程定义的代码语句,后进入的线程不会中断当前的线程,而是如同实现Join类似的功能,停止自身的线程执行。lock需要指定一个标记(即一个对象的引用),你不指定,你锁了人家大门咋办,这个要注意O(∩_∩)O哈!当线程进入锁定范围的时候就需要获得这个标记,知道你家大门被锁了,进不去了,那就等等呗。

    当然,如果我们去锁定一个实例对象的私有方法的时候,这个方法只有你这个对象可以访问,那么这个对象的引用(也就是标记)使用方法本身的对象引用就OK了,简单点就是this.锁定的就是你自家的门啦。。。

1  private void SomePrivateMethod()
2           {
3           //使用当前对象为锁定标记
4             lock(this)
5             {
6                //这个语句块(范围)中的代码是线程安全的
7              }
8           } 

   问题是我们有个锁子不一定所的都是自家的大门,指不定你就是个看大门的,哈哈。这样问题就来了,如果锁定公共成员中的一段代码,.NET推荐的方式就是使用Object成原来作为锁标记,所谓的标记你别看的那么神圣,那就是个ID而已,就是用来唯一识别的而已,不要深究这个问题。

 1 private Object myLock=new Object();
 2 public void PrintNumbers()
 3    {
 4      //使用Object成员作为锁标记
 5      lock ( myLock)
 6      {
 7         ...
 8      }
 9    }
10 } 

  好了,当我们了解完这些我们就开始解决上面的那个问题,我们分析,每次循环的线程挂起和控制台输出的部分有可能出问题,OK,那我们把它锁起来,于是我们这样做了:

 1 public void PrintNumbers()
 2     {
 3         lock (myLock)
 4         {
 5             for (int i = 0; i < 10; i++)
 6             {
 7                 Random r = new Random();
 8                 Thread.Sleep(500 * r.Next(3));
 9                 Console.Write("{0}, ", i);
10             }
11             Console.WriteLine();
12         }
13     }

我们运行看下效果:

事实证明我们成功的掌握了基本的解决多线程并发的一点点知识

本篇博客结束语:

多线程虽然可以发挥我们多核电脑的优势,即便是俺曾经用过的那台02年单核的邵阳笔记本也是支持超线程的,但是不是任何时候都可以用多线程,就好比再贵的法拉利你在我们这里的山村里你也飙不起来,但是要是让我开着拖拉机上了高速公路跑是可以跑,就是都遭人围观,于是有生之年哥决定要开个悍马,高速山村都能爽爽的跑上那么一会!!开玩笑,意思就是,不一定多核了你访问的资源就多了,看情况决定使用多线程这才是正确的决定。

如果我在写博客的过程中帮到了你,就支持自学的孩子们包括我一下!

转载于:https://www.cnblogs.com/rohelm/archive/2012/05/30/2525010.html

前线解释多线程《二》相关推荐

  1. Java读书笔记(4)-多线程(二)

    Java读书笔记(4)-多线程(二) 2016-1-2 线程通信 传统的线程通信 Object类提供了wait(),notify()和notifyAll三个方法 适用情况:synchronized修饰 ...

  2. 答案原文及解释《二五鱼水八情深,四六相约二定来》指什么意思是什么含义怎么理解解答!!

    答案原文及解释<二五鱼水八情深,四六相约二定来>指什么意思是什么含义怎么理解解答!! 云计算基础知识 无论您是在运行拥有数百万移动用户的照片共享应用程序,还是要为您的业务的关键运营提供支持 ...

  3. [java聊天室]多个客户端与服务器说话多线程(二)

    多客户端链接 之前(java聊天室一)只有第一个连接的客户端可以与服务端说话. 原因: 服务端只调用过一次accept方法,因此只有第一个客户端链接时服务端接受了链接并返回了Socket,此时可以与其 ...

  4. (三十一)java多线程二

    因为线程在执行的过程中具有一定的不确定性,在并发的时候就会出现安全问题,因此一般需要采取一定的措施来保证线程的安全,同步代码块就是其中一种方式. 以下是模拟银行取钱的多线程小例子,两个都能确保安全,但 ...

  5. python中的多进程与多线程(二)

    1.使用多线程可以有效利用CPU资源,线程享有相同的地址空间和内存,这些线程如果同时读写变量,导致互相干扰,就会产生并发问题,为了避免并发问题,绝不能让多个线程读取或写入相同的变量,因此python中 ...

  6. 黑马程序员——java基础---多线程(二)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! -------  线程间的通信:简单来说,就是多个线程在操作同一资源,但操作的动作不同. 试想一下,对于同一个资 ...

  7. 【转】细说.NET中的多线程 (二 线程池)

    上一章我们了解到,由于线程的创建,销毁都是需要耗费大量资源和时间的,开发者应该非常节约的使用线程资源.最好的办法是使用线程池,线程池能够避免当前进程中大量的线程导致操作系统不停的进行线程切换,当线程数 ...

  8. 移动开发在路上-- IOS移动开发系列 多线程二

    最近太忙没太多的时间,忙碌的码农生活空下来一点时间,都会挤出来看一些技术或者咨询的文章,废话不多说,直奔主题. 接着上一次的继续说. 定时器在多线程的使用 NSRunLoop 是线程相关的基础框架的一 ...

  9. java多线程(二)——锁机制synchronized(同步方法)

    synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中 ...

最新文章

  1. winFrom简单引用Webservice
  2. 今天开始SOA-阿里dubbo
  3. DropDownList实现可输入可选择
  4. 201114阶段二qt自定义图元类
  5. Yii2数据缓存详解
  6. ❤️❤️❤️【资料免费领取】简历模板、职场PPT模板、硬核学习资料+PDF资料(Java、Python、大数据、机器学习)❤️❤️❤️
  7. html(+css)/01/html语言基础,标记,标记语法,html文档结构
  8. tkinter Canvas画图片大坑总结
  9. go 1.5 国内下载地址
  10. c java互通rsa_C# RSA和Java RSA互通
  11. frpc在linux下开机启动,frp 设置开机自启
  12. Failed to read artifact descriptor for com.lowagie:itext:jar:2.1.7.js6
  13. 计算机网络分层协议及各层功能
  14. mssql数据库和Oracle数据库注入
  15. js实现图片放大镜效果
  16. GOOGLE 手机定位厘米挑战赛选手提到的技巧、方法总结
  17. SOLID之单一职责原则:简约而不简单
  18. 可变形卷积在视频学习中的应用:如何利用带有稀疏标记数据的视频帧
  19. 黄浩老师cpp平时作业(十一)矩阵乘法矩形类读写文件与结构体
  20. 151205苹果手机屏幕尺寸及分辨率

热门文章

  1. vue函数如何调用其他函数?_从源码中学Vue(一)生命周期中的钩子函数的那点事儿...
  2. 谷歌社交平台新漏洞威胁千万用户隐私 将提早关闭
  3. maven中snapshot版本和正式版本的区别
  4. js中json对象取键和值
  5. 结合Apache和Tomcat实现集群和负载均衡
  6. java中的浮点计算
  7. CheckBox UITableViewCell
  8. 4、列举你工作中遇到的IE6 BUG,谈谈解决方案
  9. 新兴的短距离传输技术-zigbee技术
  10. Oracle排序中NULL值处理的五种常用方法