线程系列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,无需显式调用线程的情形
线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步的更多相关文章
- 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...
- 线程系列06,通过CLR代码查看线程池及其线程
在"线程系列04,传递数据给线程,线程命名,线程异常处理,线程池"中,我们已经知道,每个进程都有一个线程池.可以通过TPL,ThreadPool.QueueUserWorkItem ...
- C# lock关键词/lock语句块、线程锁
一.lock关键词说明 1. lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁. 2. lock 语句块锁定,功能等同于 Monitor.Enter(obj): ...
- lock语句的递归问题
原文地址 前几天在网上闲逛,无意中看到有这么一道题及其答案,如下: 根据线程安全的相关知识,分析以下代码,当调用test方法时i>10时是否会引起死锁?并简要说明理由. ) { i--; tes ...
- C#线程系列讲座(5):同步技术之Monitor
在上一讲介绍了使用lock来实现线程之间的同步.实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类.先看看下面的C#源代码: public sta ...
- 左右 Java 于 finally 深度分析语句块
首先,让我们来问你一个问题:finally 声明块将运行? 很多人认为 finally 语句块是一定要运行.其中还包括了一些非常有经验的 Java 程序猿.不幸的是,没有像很多像人们想象,对于这个问题 ...
- finally语句块
finally语句块是搭配着try语句块出现的,也就说必须有try语句块才会有finally语句块,但是并不是try语句块都会搭配有finally语句块出现,我们常见的更多是try...catch.. ...
- synchronized(1)用法简介:修饰方法,修饰语句块
注意: 同一个对象或方法在不同线程中才出现同步问题,不同对象在不同线程互相不干扰. synchronized方法有2种用法:修饰方法,修饰语句块 1.synchronized方法 是某个对象实例内,s ...
- Try-Catch-Finally语句块执行问题
Try-Catch-Finally语句块执行问题 记录一个今天某公司的面试问题,其实我问题回答对了,但是面试官问我动手验证过没有,这还真没有,纯理论,被怼惨了,希望自己能变得更强大. Try-Catc ...
随机推荐
- 10 个优质的 Laravel 扩展推荐
这里有 10+ 个用来搭建 Laravel 应用的包 为何会创建这个包的列表?因为我是一个「比较懒」的开发者,在脸书上是多个 Laravel 小组的成员.平日遇到最多的问题就是开发是需要用那些包.我很 ...
- CentOS7 64位下MySQL5.7安装与配置(YUM)转
安装环境:CentOS7 64位 MINI版,安装MySQL5.7 1.配置YUM源 在MySQL官网中下载YUM源rpm安装包:http://dev.mysql.com/downloads/repo ...
- 12 打印1到最大的n位数
输入数字 n,按顺序打印出从 1 最大的 n 位十进制数.比如输入 3,则打印出 1.2.3 一直到最大的 3 位数即 999.由于 n 可能会非常大,因此不能直接用 int 表示数字,而是用 cha ...
- openfire 部署后报错: java.lang.IllegalArgumentException: interface xx is not visible from class loader
该异常是创建代理时加载接口的类加载器与创建时传入的不一致. 在本地eclipse做openfire二次开发,本地运行没错,部署到服务器上后报异常: java.lang.IllegalArgument ...
- Codeforces Round #248 (Div. 1) D - Nanami's Power Plant 最小割
D - Nanami's Power Plant 思路:类似与bzoj切糕那道题的模型.. #include<bits/stdc++.h> #define LL long long #de ...
- 【Java】 int与String类型间的相互转化
public class Test { public static void main(String[] args) { /* * int类型转String类型 */ int n1 = 9; //1. ...
- html5+css3 手机屏幕的适配css
*{ margin:0;padding:0;outline:0}a{ text-decoration:none}body,html{ font-size:20px;font-family:'Micro ...
- thinkphp3.2开启静态缓存与缓存规则设置
网站的静态缓存对大访问量有很好的缓解作用,尤其对网站的大并发,可有效的缓解数据库的压力.在thinkphp中实现静态缓存很简单,thinkphp都已经封装好了直接调用即可. 静态缓存 首先设置 H ...
- CSUOJ 1895 Apache is late again
Description Apache is a student of CSU. There is a math class every Sunday morning, but he is a very ...
- UNP学习总结(二)
本文是UNP复习系列的第二篇,主要包括了以下几个内容 UNIX系统下5种I/O模型 阻塞.非阻塞,同步.异步 epoll函数用例 一.Unix下的五种可用I/O模型 阻塞式I/O模型 阻塞式I/O是最 ...