多线程(6)线程同步
什么是线程同步
线程同步带来哪些问题
线程同步的常用解决方案
1,锁
1 /// <summary> 2 /// 线程同步计算器 3 /// </summary> 4 public class SyncCounter : CounterBase 5 { 6 /// <summary> 7 /// 全局变量 8 /// </summary> 9 public int Result = 0; 10 11 private static readonly object lockObj = new object(); 12 13 public override void Increase() 14 { 15 lock (lockObj) 16 { 17 Result++; 18 } 19 } 20 21 public override void Decrease() 22 { 23 lock (lockObj) 24 { 25 Result--; 26 } 27 } 28 }
View Code
1 /// <summary> 2 /// 线程同步计算器 3 /// </summary> 4 public class SyncCounter : CounterBase 5 { 6 /// <summary> 7 /// 全局变量 8 /// </summary> 9 public int Result = 0; 10 11 private static readonly object lockObj = new object(); 12 13 public override void Increase() 14 { 15 Monitor.Enter(lockObj); 16 try 17 { 18 Result++; 19 } 20 finally 21 { 22 Monitor.Exit(lockObj); 23 } 24 } 25 26 public override void Decrease() 27 { 28 Monitor.Enter(lockObj); 29 try 30 { 31 Result--; 32 } 33 finally 34 { 35 Monitor.Exit(lockObj); 36 } 37 } 38 }
View Code
完整代码:
1 namespace ConsoleApplication28 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //同时发起3个异步线程 8 Console.WriteLine("普通(非线程同步)计算器测试..."); 9 var normalCounter = new NormalCounter(); 10 var tasks = new List<Task>(); 11 var task1 = Task.Factory.StartNew(() => 12 { 13 TestCounter(normalCounter); 14 }); 15 tasks.Add(task1); 16 17 var task2 = Task.Factory.StartNew(() => 18 { 19 TestCounter(normalCounter); 20 }); 21 tasks.Add(task2); 22 23 var task3 = Task.Factory.StartNew(() => 24 { 25 TestCounter(normalCounter); 26 }); 27 tasks.Add(task3); 28 29 30 Task.WaitAll(tasks.ToArray()); 31 Console.WriteLine("NormalCounter.Result:" + normalCounter.Result); 32 Console.WriteLine("*******************************************"); 33 34 Console.WriteLine("线程同步计算器测试..."); 35 var syncCounter = new SyncCounter(); 36 var tasks1 = new List<Task>(); 37 task1 = Task.Factory.StartNew(() => 38 { 39 TestCounter(syncCounter); 40 }); 41 tasks1.Add(task1); 42 43 task2 = Task.Factory.StartNew(() => 44 { 45 TestCounter(syncCounter); 46 }); 47 tasks1.Add(task2); 48 49 task3 = Task.Factory.StartNew(() => 50 { 51 TestCounter(syncCounter); 52 }); 53 tasks1.Add(task3); 54 55 Task.WaitAll(tasks1.ToArray()); 56 Console.WriteLine("SyncCounter.Result:" + syncCounter.Result); 57 58 Console.ReadKey(); 59 } 60 61 /// <summary> 62 /// 63 /// </summary> 64 /// <param name="counter"></param> 65 static void TestCounter(CounterBase counter) 66 { 67 //100000次加减 68 for (int i = 0; i < 100000; i++) 69 { 70 counter.Increase(); 71 counter.Decrease(); 72 } 73 } 74 } 75 76 /// <summary> 77 /// 计算器基类 78 /// </summary> 79 public abstract class CounterBase 80 { 81 /// <summary> 82 /// 加 83 /// </summary> 84 public abstract void Increase(); 85 86 /// <summary> 87 /// 减 88 /// </summary> 89 public abstract void Decrease(); 90 } 91 92 /// <summary> 93 /// 普通计算器 94 /// </summary> 95 public class NormalCounter : CounterBase 96 { 97 /// <summary> 98 /// 全局变量 99 /// </summary> 100 public int Result = 0; 101 102 public override void Increase() 103 { 104 Result++; 105 } 106 107 public override void Decrease() 108 { 109 Result--; 110 } 111 112 } 113 114 /// <summary> 115 /// 线程同步计算器 116 /// </summary> 117 public class SyncCounter : CounterBase 118 { 119 /// <summary> 120 /// 全局变量 121 /// </summary> 122 public int Result = 0; 123 124 private static readonly object lockObj = new object(); 125 126 public override void Increase() 127 { 128 lock (lockObj) 129 { 130 Result++; 131 } 132 } 133 134 public override void Decrease() 135 { 136 lock (lockObj) 137 { 138 Result--; 139 } 140 } 141 } 142 }
View Code
lock关键字揭密:
从上图可以得出以下结论:
lock关键字内部就是使用Monitor类(或者说lock关键字是Monitor的语法糖),使用lock关键字比直接使用Monitor更好,原因有二。
1,lock语法更简洁。
2,lock确保了即使代码抛出异常,也可以释放锁,因为在finally中调用了Monitor.Exit方法。
2,信号同步
下面是使用信号同步机制的一个简单的例子,如下代码:
1 namespace WindowsFormsApplication1 2 { 3 public partial class Form1 : Form 4 { 5 //信号 6 AutoResetEvent autoResetEvent = new AutoResetEvent(false); 7 8 public Form1() 9 { 10 InitializeComponent(); 11 12 CheckForIllegalCrossThreadCalls = false; 13 } 14 15 /// <summary> 16 /// 开始 17 /// </summary> 18 /// <param name="sender"></param> 19 /// <param name="e"></param> 20 private void button1_Click(object sender, EventArgs e) 21 { 22 Task.Factory.StartNew(() => 23 { 24 this.richTextBox1.Text+="线程启动..." + Environment.NewLine; 25 this.richTextBox1.Text += "开始处理一些实际的工作" + Environment.NewLine; 26 Thread.Sleep(3000); 27 28 this.richTextBox1.Text += "我开始等待别的线程给我信号,才愿意继续下去" + Environment.NewLine; 29 autoResetEvent.WaitOne(); 30 this.richTextBox1.Text += "我继续做一些工作,然后结束了!"; 31 }); 32 } 33 34 /// <summary> 35 /// 信号同步 36 /// </summary> 37 /// <param name="sender"></param> 38 /// <param name="e"></param> 39 private void button2_Click(object sender, EventArgs e) 40 { 41 //给在autoResetEvent上等待的线程一个信号 42 autoResetEvent.Set(); 43 } 44 } 45 }
View Code
运行效果:
1,线程阻塞,等待信号。
2,主线程发送信号,让线程继续执行。
3,线程安全的集合类
- ConcurrentQueue 线程安全版本的Queue【常用】
- ConcurrentStack线程安全版本的Stack
- ConcurrentBag线程安全的对象集合
- ConcurrentDictionary线程安全的Dictionary【常用】
多线程(6)线程同步相关推荐
- 3、Linux多线程,线程同步(转)
3.Linux多线程,线程同步 5)线程私有数据 进程内的所有线程共享进程的数据空间,因此全局变量为所有线程所共有.但有时线程也需要保存自己的私有数据,这时可以创建线程私有数据(Thread-spec ...
- C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent
C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent 本章概要: 1:终止状态和非终止状态 2:AutoResetEvent和ManualResetE ...
- VC++ MFC 多线程及线程同步(详细、全面总结!)
更多详情:http://blog.csdn.net/whyacinth/ VC++ MFC 多线程及线程同步 关键词: MFC 多线程及线程同步 ...
- Java多线程之线程同步机制(锁,线程池等等)
Java多线程之线程同步机制 一.概念 1.并发 2.起因 3.缺点 二.三大不安全案例 1.样例一(模拟买票场景) 2.样例二(模拟取钱场景) 3.样例三(模拟集合) 三.同步方法及同步块 1.同步 ...
- MFC 多线程及线程同步
一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...
- cocos2dx多线程以及线程同步 与 cocos2dx内存管理与多线程问题
cocos2d-x引擎在内部实现了一个庞大的主循环,每帧之间更新界面,如果耗时的操作放到了主线程中,游戏的界面就会卡,这是不能容忍的,游戏最基本的条件就是流畅性,这就是为什么游戏开发选择C++的原因. ...
- 多线程,线程同步,synchronized关键字的用法
一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...
- NET多线程探索-线程同步和通信
NET中各种线程同步方法 在NET多线程开发中,有时候需要多个线程协调工作,完成这个步骤的过程称为"同步". 使用同步的主要原因: 1.多个线程访问同一个共享资源. 2.多线程写入 ...
- Java多线程(线程同步)
多线程编程很容易出现"错误情况",这是由系统的线程调度具有一定的随机性造成的,不过即使程序偶然出现问题,那也是由于编程不当引起.使用多个线程访问同一个数据时很容易出现此类状况,因此 ...
最新文章
- opencv 环境变量
- java 中调用window系统中的文件,或者执行命令(shell、.CMD、.EXE)并获取返回值
- 原创 | OpenAPI 标准规范
- cocostudio 实现换行功能的label (文本区) lua
- 阿里数据库内核月报:2016年03月
- 期待!小米电视5官曝新功能:可准确识别家中每一个人
- Figma插件开发-生成Gif
- Java练手项目(好玩又有趣)
- linux下codeblock使用注意事项 (deepin)
- 国家网络信息安全战略三步曲
- delphi技巧--分离汉字和英文字母
- 前端学习-jquery-实现点击button对文本的add及detele
- likeshop单商户SAAS商城系统无限多开
- Cherry键盘外接Mac command按键失灵
- 【博士论文】深度学习的对抗攻击与鲁棒性测评
- windows如何截屏
- MOOS-ivp简介
- 路由器交换机存储部件浅析
- C语言超出类型数值范围的表示方法
- Ubuntu子系统上安装miniconda.sh 438、444报错
热门文章
- c 语言中浮点数舍入,浮点数在C中舍入,我不明白为什么
- matplotlib 中文_详解Matplotlib中文字符显示问题
- python web框架对比_Python六大开源框架对比
- 无线对讲调度服务器,无线对讲系统解决方案
- mq多个消费者消费一个消息_一个普通消费者的米家产品使用感受
- java mp4 视频时间戳_MP4文件中音视频时间戳的计算
- linux软件包管理工具,Linux 软件包管理器-----yum配置详解一
- php+include+引入html文件,include引入文件
- java文件客户端下载_使用Java写一个minio的客户端上传下载文件
- FilterListener笔记