线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步
假设多个线程共享一个静态变量,如果让每个线程都执行相同的方法每次让静态变量自增1,这样的做法线程安全吗?能保证自增变量数据同步吗?本篇体验使用lock语句块和Interlocked类型方法保证自增变量的数据同步。
□ 线程不安全、数据不同步的做法
class Program
{static int sum = 0;static void Main(string[] args){Stopwatch watch = new Stopwatch();
watch.Start();Parallel.For(0, Environment.ProcessorCount, i =>{for (int j = 0; j < 100000000; ++j){AddOne();}});watch.Stop();Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);
Console.ReadKey();}static void AddOne(){sum++;}}
○ 变量sum是静态的,供所有线程共享
○ Parallel.For提供并行循环, Environment.ProcessorCount表示处理器的处理,如果有4个CPU,就做4组循环
我们发现,结果不是我们期望的400000000,也就是说,在这种情况下的静态变量自增不是线程安全的,换句话说,无法保证共享数据的同步。
□ 通过lock语句块保持数据同步
class Program
{static int sum = 0;private static readonly object o = new object();static void Main(string[] args){Stopwatch watch = new Stopwatch();
watch.Start();Parallel.For(0, Environment.ProcessorCount, i =>{for (int j = 0; j < 100000000; ++j){AddOne();}});watch.Stop();Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);
Console.ReadKey();}static void AddOne(){lock (o)
{sum++;}}}
这一次,使用lock语句块得到了预期的结果。
□ 使用Interlocked保持数据同步
对于int或long类型变量的自增,并且保证类型安全,可以使用Interlocked类。提供的方法包括:
○ int Interlocked.Increment(ref int location),自增1
○ long Interlocked.Increment(ref long location),自增1
○ int Interlocked.Decrement(ref int location),自减1
○ long Interlocked.Decrement(ref long location),自减1
○ int Interlocked.Add(ref int location, int value),自增一个值
○ long Interlocked.Add(ref long location, long value),自增一个值
class Program
{static int sum = 0;static void Main(string[] args){Stopwatch watch = new Stopwatch();
watch.Start();Parallel.For(0, Environment.ProcessorCount, i =>{for (int j = 0; j < 100000000; ++j){AddOne();}});watch.Stop();Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);
Console.ReadKey();}static void AddOne(){Interlocked.Increment(ref sum);
}}
使用Interlocked也能保证线程安全、数据同步,但耗时较长。
总结:
○ lock语句块和Interlocked类型方法都能保证自增变量的线程安全、数据同步
○ Interlocked类型方法只适用于int,long类型变量,有一定的局限性
线程系列包括:
线程系列01,前台线程,后台线程,线程同步
线程系列02,多个线程同时处理一个耗时较长的任务以节省时间
线程系列03,多线程共享数据,多线程不共享数据
线程系列04,传递数据给线程,线程命名,线程异常处理,线程池
线程系列05,手动结束线程
线程系列06,通过CLR代码查看线程池及其线程
线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步
线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
线程系列10,无需显式调用线程的情形
相关文章
- 操作数据库的时候,使用自带的DbProviderFactory类 (涉及抽象工厂和工厂方法)
- Python __missing__ 魔法方法
- Iterator to list的三种方法
- MVC 之HTML辅助方法
- C#使用oledb连接excel运行Insert Into语句出现“操作必须使用一个可更新的查询”的解决的方法
- Python 使用ntplib库同步校准当地时间的方法 (NTP)
- Visual Studio 2015 Update 1 安装到最后 KB3022398 错误解决方法
- IIS7.5上的REST服务的Put操作发生HTTP Error 405.0 - Method Not Allowed 解决方法
- 地球引擎初级教程——Python API 介绍何安装(通过 Anaconda方法安装)
- 【TLD】改进后的TLD视频目标跟踪方法的MATLAB仿真
- Windows无法连接共享打印机,错误码:0x0000011b的解决方法
- git本地分支目录和远程服务器的分支目录不一样的同步方法[转】
- mvn编译“Cannot find matching toolchain definitions for the following toolchain types“报错解决方法
- Qt中线程同步的几种方法详解
- C# 实现多线程的同步方法详解
- Python中的get和set方法
- 全网最通俗易懂的「插屏广告」接入方法
- linux实现共享内存同步的四种方法
- 《代码整洁之道》—第13章13.6节警惕同步方法之间的依赖
- 2种方法解决mysql主从不同步[转载]
- Django 4.x Auth 身份验证使用示例和配置方法
- 扩展thinkphp5的redis类方法
- 一种Hudi on Flink动态同步元数据变化的方法
- 《软件建模与设计: UML、用例、模式和软件体系结构》一一1.5 COMET:一种基于UML的软件应用建模和设计方法
- homestead 代码与本地代码不同步的解决方法
- 小技巧随手记:一行代码实现星级评分、同步阻塞实现sleep函数、一行代码生成随机字符串(唯一ID/Number.prototype.toString([radix])用法)、获取浏览器Cookie的值、颜色RGB转十六进制、使用数字分隔符、最快获取dom方法(ID同名变量获取dom元素)、带命名空间的事件绑定
- Hadoop创始人Doug Cutting寄语2017:五种让开源项目成功的方法
- Unity 工具类 之 简单的异步场景加载(包含加载进度和同步加载方法)类 LoadSceneManager 实现
- JAVA中线程同步的方法(7种)汇总
- [CareerCup] 16.6 Synchronized Method 同步方法
- C#多线程问题(从不同步的代码块中调用了对象同步方法。)
- 归纳一下:C#线程同步的几种方法
- Oracle、SQL Server、MySQL分页方法