故事发生在前几天,我被对象拖着去看房,对于我这种陈年老宅来说,那就是噩梦啊,虽然有诸多不满,但还是去了。出没于各大新旧楼宇之间,看了一天,要到下午5点左右,终于看好了一个新楼盘,然后看看户型,问问朝向等。都觉得还不错,就准备入手,然后自己还各种科普买房知识,以为准备已充分,合同签了,交了钱,就完事,高高兴兴地就回家了。

  第二天,我对象拿出合同准备再仔细看了看合同内容,然后猛地才发现,合同居然没盖章,这下可把我急着了,这岂不是可以一房多卖,合同都不跟我们盖章,那岂不是合同未生效啊,太气人了,于是赶紧找他们理论,吵吵半天之后盖了章。

  于是乎,我想到了两个问题

  销售员未和我们协商到最后一刻,然后由另一个销售接手(多个线程同时操作同一个数据源)

  合同未完成,就给我们(多线程数据的一致性,lock)

  在多任务系统中,每个独立执行的程序称为进程,也就是正在进行的程序,现在使用的操作系统一般都是多任务的,即能够同时执行多个应用程序,实际情况是,操作系统负责对CPU等设备的资源进行分配和管理,虽然这些设备某一时刻只能做一件事,但以非常小的时间间隔交替执行多个程序,就可以给人以同时执行多个程序的感觉,怎么证明这一点呢?

 1 class TestThread
 2 {
 3     public static void Main(string[] args)
 4     {
 5         Thread t = new Thread(new ThreadStart(new Thread1().Run));
 6         try
 7         {
 8             t.Start();
 9         }
10         catch (Exception ex)
11         {
12             throw ex;
13         }
14
15         while (true)
16         {
17             Console.WriteLine("主线程正在执行...");
18         }
19     }
20 }

 1 class Thread1
 2 {
 3     public void Run()
 4     {
 5         while (true)
 6         {
 7             Console.WriteLine("子线程正在执行...");
 8         }
 9     }
10 }

执行结果:可以看到操作系统是轮流分配CPU执行主线程和子线程的

让一个线程中在执行到lock的代码块时不会切换CPU,而是执行完之后才允许切换CPU到另一个线程,保证数据的完整性

什么情况下会让一房多卖呢,现在我们就用多线程模拟下一房多卖的场景

假设,有100套房子要卖,同时有四个销售员在卖,此时的代码如下:

 1 class TestThread
 2 {
 3     public static void Main(string[] args)
 4     {
 5         // 一房多卖
 6         Thread t1 = new Thread(new ThreadStart(new Thread2().Run));
 7         t1.Name = "销售员A";
 8         t1.Start();
 9         Thread t2 = new Thread(new ThreadStart(new Thread2().Run));
10         t2.Name = "销售员B";
11         t2.Start();
12         Thread t3 = new Thread(new ThreadStart(new Thread2().Run));
13         t3.Name = "销售员C";
14         t3.Start();
15         Thread t4 = new Thread(new ThreadStart(new Thread2().Run));
16         t4.Name = "销售员D";
17         t4.Start();
18     }
19 }

 1 class Thread2
 2 {
 3     public int house = 100;
 4
 5     // 重点!!!
 6     // string是引用类型,可以当作lock锁定对象,其他值类型是不能用来lock的
 7     public string lockObj = string.Empty;
 8
 9     // 会抛出异常 error CS0185: “int”不是 lock 语句要求的引用类型
10     // public int lockInt = 0;
11
12     public void Run()
13     {
14         while (true)
15         {
16             lock (lockObj)
17             {
18                 if (house > 0)
19                 {
20                     // 重现存在线程不同步,导致的线程安全问题
21                     // 解决办法,加入线程同步锁
22                     Thread.Sleep(10);
23                     Console.WriteLine(Thread.CurrentThread.Name + " 正在卖 " + house + "号房");
24                     house--;
25                 }
26             }
27         }
28     }
29 }

执行结果:同一个房子被卖了三次,原因就在于三个销售员,没有用同一个房源,而且互相之间也没有通信,不知道对方卖了那个房子

接下来我们就要让四个销售员都卖同一个房源,并且要在销售之前加上锁,防止别人和自己同时在卖一套房子

 1 class TestThread
 2 {
 3     public static void Main(string[] args)
 4     {
 5         // 一房一卖
 6         ThreadStart method = new ThreadStart(new Thread2().Run);
 7         Thread t1 = new Thread(method);
 8         t1.Name = "销售员A";
 9         t1.Start();
10         Thread t2 = new Thread(method);
11         t2.Name = "销售员B";
12         t2.Start();
13         Thread t3 = new Thread(method);
14         t3.Name = "销售员C";
15         t3.Start();
16         Thread t4 = new Thread(method);
17         t4.Name = "销售员D";
18         t4.Start();
19     }
20 }

 1 class Thread2
 2 {
 3     public int house = 100;
 4
 5     // 重点!!!
 6     // string是引用类型,可以当作lock锁定对象,其他值类型是不能用来lock的
 7     public string lockObj = string.Empty;
 8
 9     // 会抛出异常 error CS0185: “int”不是 lock 语句要求的引用类型
10     // public int lockInt = 0;
11
12     public void Run()
13     {
14         while (true)
15         {
16             lock (lockObj)
17             {
18                 if (house > 0)
19                 {
20                     // 重现存在线程不同步,导致的线程安全问题
21                     // 解决办法,加入线程同步锁
22                     Thread.Sleep(10);
23                     Console.WriteLine(Thread.CurrentThread.Name + " 正在卖 " + house + "号房");
24                     house--;
25                 }
26             }
27         }
28     }
29 }

执行结果:房子一房多卖的情况已被解决

多个线程互相等待对方的锁定标识未被释放,就会产生死锁

 1 class TestThread
 2 {
 3     public static void Main(string[] args)
 4     {
 5         // 重现死锁问题
 6         Thread3 thread3 = new Thread3();
 7         Thread t1 = new Thread(new ThreadStart(thread3.Run));
 8         t1.Name = "销售员A";
 9         t1.Start();
10         Thread.Sleep(1);
11         thread3.lockObj = "中介";
12         Thread t2 = new Thread(new ThreadStart(thread3.Run));
13         t2.Name = "销售员B";
14         t2.Start();
15     }
16 }

 1 class Thread3
 2 {
 3     public string lockObj = string.Empty;
 4     public int house = 100;
 5
 6     public void Run()
 7     {
 8         if (lockObj == "中介")
 9         {
10             while (true)
11             {
12                 lock (this)
13                 {
14                     if (house > 0)
15                     {
16                         // 重现存在线程不同步,导致的线程安全问题
17                         // 解决办法,加入线程同步锁
18                         Thread.Sleep(10);
19                         // 死锁问题
20                         lock (lockObj) { }
21                         Console.WriteLine(lockObj + "的" + Thread.CurrentThread.Name + " 正在卖 " + (house--) + "号房");
22                         ;
23                     }
24                 }
25             }
26         }
27         else
28         {
29             while (true)
30             {
31                 lock (lockObj)
32                 {
33                     if (house > 0)
34                     {
35                         // 重现存在线程不同步,导致的线程安全问题
36                         // 解决办法,加入线程同步锁
37                         Thread.Sleep(10);
38                         // 死锁问题
39                         lock (this) { }
40                         Console.WriteLine("内部的" + Thread.CurrentThread.Name + " 正在卖 " + (house--) + "号房");
41                     }
42                 }
43             }
44         }
45     }
46 }

执行结果:结果显示,多线程已经卡住了,发生了死锁的情况,原因就是双方都等着对方先出售,自己再卖

waitOne 告诉当前线程放弃CPU并进入睡眠状态直到其他线程进入同一个监视器并调用Set为止

多线程之间难免会遇到需要相互打交道的时候,举个例子,开发商为了防止销售员偷懒,就交替为销售员分配客户,下面我们就用代码去模拟下这个场景

 1 class ThreadCommunation
 2 {
 3     public static void Main(string[] args)
 4     {
 5         // 实现销售员A和销售员B交替分配客户
 6         Q q = new Q();
 7
 8         // 测试多线程之前的通信
 9         new Thread(new ThreadStart(new Producer(q).Run)).Start();
10         new Thread(new ThreadStart(new Customer(q).Run)).Start();
11     }
12 }

 1 /// <summary>
 2 /// DTO
 3 /// </summary>
 4 class Q
 5 {
 6     private EventWaitHandle e = new AutoResetEvent(false);
 7     private readonly object lockA = new object();
 8     private readonly object lockB = new object();
 9     private string seller = "unknown";
10     private string house = "unknown";
11     private bool bFull = false;
12     private bool isStop = false;
13
14     public Q()
15     {
16
17     }
18
19     public Q(string seller, string house)
20     {
21         this.seller = seller;
22         this.house = house;
23     }
24
25     public void Stop()
26     {
27         this.isStop = true;
28     }
29
30     public void Put(string seller, string house)
31     {
32         // 重点!!!
33         // 不能用同一个锁定标识,会产生死锁
34         lock (lockA)
35         {
36             if (this.bFull)
37             {
38                 // 等待被另一个线程清空后再插入数据
39                 e.WaitOne();
40             }
41             this.seller = seller;
42             Thread.Sleep(1);
43             this.house = house;
44             this.bFull = true;
45
46             // 通知等待的线程可以继续执行
47             e.Set();
48         }
49     }
50
51     public void Get()
52     {
53         if (!this.isStop)
54         {
55             // 重点!!!
56             // 不能用同一个锁定标识,会产生死锁
57             lock (lockB)
58             {
59                 if (!this.bFull)
60                 {
61                     // 等待被另一个线程清空后再插入数据
62                     e.WaitOne();
63                 }
64                 Console.WriteLine(this.ToString());
65                 this.bFull = false;
66
67                 // 通知等待的线程可以继续执行
68                 e.Set();
69             }
70         }
71     }
72
73     public override string ToString()
74     {
75         return "销售员:" + this.seller + "正在接待:" + this.house + "号客户";
76     }
77 }

 1 /// <summary>
 2 /// 生产者
 3 /// </summary>
 4 class Producer
 5 {
 6     private Q q;
 7
 8     public Producer(Q q)
 9     {
10         this.q = q;
11     }
12
13     public void Run()
14     {
15         int i = 0;
16         int house = 100;
17         while (true)
18         {
19             if (house > 0)
20             {
21                 if (i == 0)
22                 {
23                     q.Put("销售员A", (house--).ToString());
24                 }
25                 else
26                 {
27                     q.Put("销售员B", (house--).ToString());
28                 }
29
30                 i = (i + 1) % 2;
31             }
32             else
33             {
34                 q.Stop();
35             }
36         }
37     }
38 }

 1 /// <summary>
 2 /// 消费者
 3 /// </summary>
 4 class Customer
 5 {
 6     private Q q;
 7
 8     public Customer(Q q)
 9     {
10         this.q = q;
11     }
12
13     public void Run()
14     {
15         while (true)
16         {
17             q.Get();
18         }
19     }
20 }

执行结果:可以看出销售员A和销售员B正在交替接待客户

总结:理论不是太多,全是实践而来的干货,希望对大家对C#的了解有所帮助

转载于:https://www.cnblogs.com/Zyj12/p/11527913.html

一次买房子血淋淋的教训相关推荐

  1. 1.5编程基础之循环控制_16买房子

    http://noi.openjudge.cn/ch0105/16/ /* 1.5编程基础之循环控制_16买房子_2020.03.31-02 http://noi.openjudge.cn/ch010 ...

  2. OpenJudge NOI 1.5 16:买房子

    [题目链接] OpenJudge NOI 1.5 16:买房子 [题目考点] 1. 循环求幂 设变量r初始值为1:int r = 1; 循环n次每次循环中输入变量a,将r的值设为r*a:r *= a; ...

  3. 买房子还是不买房子,这是一个问题

    买房子还是不买房子,这是一个问题 昨天是周日,也是农历五月三十,我的同事孙洋选择了这天,举办婚礼. 我和小M也去参加了.婚礼上播放的关于小夫妻相识相知的电视短片很搞笑,也很温馨,席下众多单身男女不禁感 ...

  4. 血淋淋的教训—将Vue项目打包成app的跨域问题

    1 devServer: { 2 host: '192.168.1.58', 3 port: 9999, 4 historyApiFallback: true, 5 noInfo: true, 6 o ...

  5. 老公年收入百万,却不愿拿出二十万帮我弟弟买房子,我该离婚吗?

    首先,我们都应该明白一点的就是,老公对自己媳妇儿的家人没有赡养义务,法律上,法律上也是这么规定的,也是合法的. 如果说要有帮助,这只是情义问题,自己自愿的. 不管老公一年挣多少钱,与娘家人没有一点关系 ...

  6. Bailian4022 买房子【迭代】

    4022:买房子 总时间限制: 1000ms 内存限制: 65536kB 描述 某程序员开始工作,年薪N万,他希望在中关村公馆买一套60平米的房子,现在价格是200万,假设房子价格以每年百分之K增长, ...

  7. windows 10 安装 db2 v11.1(血淋淋的教训)

    学校的一个数据库作业需要用到db2,但老师给的版本只能装在xp上,,其他同学有装虚拟机的,但我的电脑本来就装了一个linux,内存已经不够耗了,于是乎我开始了漫长而痛苦的安装之路....血淋淋的教训促 ...

  8. 7-154 置点不动产——认真学习,努力工作买买房子吧

    7-154 置点不动产--认真学习,努力工作买买房子吧 某程序员开始工作,年薪N万,他希望在ZG村公馆买一套60平米的房子,现在价格是200万,假设房子价格以每年百分之K增长,并且该程序员未来年薪不变 ...

  9. PTA 7-154 置点不动产——认真学习,努力工作买买房子吧

    PTA 7-154 置点不动产--认真学习,努力工作买买房子吧 分数 10 作者 焦晓军 单位 重庆科技学院 某程序员开始工作,年薪N万,他希望在ZG村公馆买一套60平米的房子,现在价格是200万,假 ...

最新文章

  1. 你真懂JavaScript吗?
  2. 计算机电路门,7.3 门电路计算机操作系统原理.pdf
  3. 计算机视觉迎新突破?谷歌AI模型打破现有CNNs精度
  4. 【Flutter】Flutter 应用创建运行 ( Android Studio 创建 / 运行 Flutter 应用 | 命令行创建 / 运行 Flutter 应用 )
  5. 集群与存储 LVS的集群
  6. 解决嵌入式开发过程中开发板与虚拟机的网络通信问题
  7. jquery开关灯案例_全屋开关插座布局讲解,自己规划怕遗漏,手把手教你,很详细...
  8. android 绘画笔迹回放_随时记录分享书写笔迹,EverPEN高级版套装体验
  9. QQ浏览器如何修改截屏快捷键?QQ浏览器修改截屏快捷键的方法
  10. vue 父组件获取接口值传到子组件_vue父组件异步获取数据传给子组件的方法
  11. 飞鸽传书2011看到一篇国外的博客
  12. linux内核开启overlay,Linux-overlay启动挂载为只读或写文件异常
  13. mac软件意外退出怎么解决_Mac 软件常见问题解决方法汇总
  14. 32位oracle10,『三思笔记』-- Solaris10下安装32位Oracle10g -- Solaris 10下安装ORACLE10G
  15. python爬虫框架教程_python爬虫框架有哪些
  16. WSO2身份服务中的关键概念一: 单点登录与身份联合
  17. VC++的Unicode编程
  18. 基于STM32F103的单相在线式不间断电源设计
  19. 树莓派+无人机Tello+计算棒实时飞行检测实现
  20. 物流公司的发出时间在哪里查询,快递单号查询方法

热门文章

  1. 强化学习-利用Q-Learning算法玩走方格游戏(C++)
  2. Python数据处理课程设计-房屋价格预测-代码
  3. curaengine linux编译,Cura Engine
  4. 什么是ICP经营许可证?
  5. canvas模拟实现高德地图的部分功能
  6. 谈谈火车票信息泄漏问题
  7. 威5创非凡,领航再出击 | 新华三集团成立五周年庆
  8. Python网络爬虫和信息提取
  9. amcharts的使用介绍
  10. sonarqube中 项目名称 问题