Volatile vs. Interlocked vs. lock
今天在stackoverflow上看到一个关于Volatile, Interlock, Lock的问题,发现回答的特别好,所以就想到把它翻译一下, 希望给那些对它们有疑惑的人提供点帮助
:假设有一个类,它含有一个可以被多线程访问的public int counter 字段, 这个数字只会增加或减少。
当去增加这个字段的时候,应该采用下面哪个方案,为什么?
- lock(this.locker) this.counter++;
- Interlocked.Increment(ref this.counter);
- Change the access modifier of counter to public volatile
:
最糟糕(实际上都不能起作用)
Change the access modifier of counter to public volatile
这种方式实际上根本不安全,关于volatile的重点是:运行在多个CPU上的多个线程会缓冲数据和重新排列执行的指令。
如果它是非volatile, 当CPU A增加了一个值, CPU B需要等一会才能看到增加的值,这可能导致问题的出现。
如果它是volatile,就能确保两个CPU能在相同的时间看到相同的值。但它并不能避免交叉的读写操作。
给一个变量增加值,实际上需要三步
1. 读, 2. 增加 3.写
假设线程A 读取 counter 的值为1,还没有准备增加,这时线程B也读取counter 的值为1, 然后两个线程都开始执行增加,写的操作。最终counter 的值为2. 这是不对的,两个线程都做了增加操作,正确的结果应该是3. 所以把它标志为volatile根本就是不安全的。
比较好
lock(this.locker) this.counter++;
这种方式是安全的(当然你要记得lock所有你想访问this.counter的地方)。它防止其它任何线程去执行被lock锁住的代码。并且它还能防止上面提到的多CPU指令排序的问题。但问题是,lock在性能上比较慢,并且如果你在其它的一些不相干的地方也用了lock,可能会导致阻塞你的其它线程。
最好
Interlocked.Increment(ref this.counter);
这个是安全的,也是非常高效的。它执行读,增加,写三个操作在一个原子中,不会在中间被打断。因为它不影响其它的代码,你也不需要记住其它地方的Lock. 并且它还非常快(正如MSDN说的,在现在的CPU上,它常常只是一个指令)。
但是我不完全确定它能否也能解决CPU的指令排序的问题,还是需要结合volatile和这个increment一起使用。
补充:到底volatile是擅长解决什么问题的?
既然volatile不能防止多线程的问题,那它能干啥用?举个很好的例子,假设你有两个线程,一个总是往一个变量中进行写操作,假设这个变量为queneLength, 另一个总是从这个变量中读取数据。如果queueLenght不是volatile的, 线程A可能读了5次,但是线程B可能看到的是延迟的数据,甚至可能看到错误的顺序的数据。一个方案就是用lock, 但是在这种情况系你也可以用volatile. 这样能确保线程B总能看到线程A写的最新数据,但是这个这个逻辑仅仅在你写的时候没有读,读的时候没有写时才有效。一旦多个线程都要做读-修改-写的操作,你需要用Interlocked或者用lock.
Volatile vs. Interlocked vs. lock的更多相关文章
- 多线程中的锁系统(二)-volatile、Interlocked、ReaderWriterLockSlim
上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了,本篇主要介绍下升级锁和原子操作. 阅读目录 volatile Interlocked ReaderWriterLo ...
- 多线程---再次认识volatile,Synchronize,lock
在多线程中我们常用的保证共享变量的方法有很多,现在我们介绍其中的一种,volatile,也是效率最高的一种. 一 .volatile的意义: 为了确保共享变量能被正确和一 ...
- volatile和synchronized与lock的理解
volatile 特征: a:可见性:一个线程修改了某个共享变量的值,其他线程能够立马得知这个修改. b:禁止特定的处理器重排序. volatile的内存语义: 1.当写一个volatile变量的时候 ...
- volatile 和 Interlocked
class Volatile_Test3 { ; public static void Test() { count = ; Task[] tasks = ]; ; i < tasks.Leng ...
- volatile、synchronized、lock有什么区别,以及在哪些场景下使用哪种方式?
[转]JVM锁机制volatile/synchronized/lock 1.volatile实现原理 (1)聊聊并发(一)——深入分析Volatile的实现原理 --硬件级别锁实现,Lock前缀指令会 ...
- Java并发编程知识点总结Volatile、Synchronized、Lock实现原理
Volatile关键字及其实现原理 在多线程并发编程中,Volatile可以理解为轻量级的Synchronized,用volatile关键字声明的变量,叫做共享变量,其保证了变量的“可见性”以及“有序 ...
- 线程、volatile与synchronized、Lock
目录 线程 1.概念: 2.线程生命周期: 3.线程调度 4.线程实现 4.1.实现方式 4.2.之间的区别: 5.线程安全 5.1.volatile与synchronized 5.1.synchro ...
- C# 基础回顾: volatile 关键字
有些人可能从来没看到过这个关键字,这也难怪,因为这个关键字并不常用.那这个关键字到底有什么用呢? 我在网上搜索这个关键字的时候,发现很多朋友都有一个错误的认识 ------ 认为这个关键字可以防止并发 ...
- C# Interlocked 笔记
无锁代码下,在读写字段时使用内存屏障往往是不够的.在 64 位字段上进行加.减操作需要使用Interlocked工具类这样更加重型的方式.Interlocked也提供了Exchange和Compare ...
随机推荐
- EXCEL插件
http://www.cnblogs.com/brooks-dotnet/category/233027.html http://www.360doc.com/content/15/0713/00/1 ...
- shell跑一个PHP脚本的简单命令
最近在做一个刷数据库的小功能,需要批量添加到不同的表中,写好PHP文件之后,登录到某一个服务器上面 上传文件的命令:rz 会出现一个弹框可以选择要上传的文件 执行文件并报错误的命令:/usr/loca ...
- Asp.net主题(theme)和皮肤(skin)的使用
asp.net 的服务器端控件提供了多种样式的设计,如果对每个控件都单独设置,是比较繁琐的事情,所以微软也提供了针对这些服务器端控件的样式管理,其实也可以通过 css来控制部分服务器端控件的样式,比如 ...
- DNS服务器的原理
当用户去访问一个网站(百度)的时候,首先去请求dns服务器,根据对应的域名返回所在ip,然后再使用ip去访问自己所在服务器空间.简单的说,DNS服务器就像114客服,dns服务器是树状结构的,dns服 ...
- Express在windows IIS上部署详解
最近公司在用Express+angularjs+wcf开发系统,让我在windows上部署系统,遇到不少问题,不过最后还是解决了,在IIS上部署系统, 首先windows需安装以下软件: 1.node ...
- jQuery实现页面元素智能定位
实现过程 Js侦听滚动事件,当页面滚动的距离(页面滚动的高度)超出了对象(要滚动的层)距离页面顶部的高度,即要滚动的层到达了浏览器窗口上边缘时,立即将对象定位属性position值改成fixed(固定 ...
- linux常用命令(查看某些软件是否已安装)
查看imap是否已安装 rpm -qa | grep imap 以下为未安装的情形: 检查是否已安装sendmail: rpm -qa | grep sendmail 以下为已安装的返回:
- 关于javascript输出中文乱码的问题
今天找到一个引导效果.原来是用英文进行引导.但是我改了里面的英文为汉字就出现乱码的情况.英文提示是在js页面里面完成的.所以最后的解决办法 就是把js文件用记事本打开,然后把文件另存为utf-8的格式 ...
- C#遍历所有的Textbox控件并赋值为String.Empty
foreach (Control control in this.Controls) { if (control.GetType().Name.Equals("TextBox")) ...
- ecshop--加载初始化文件
define('IN_ECS', true);require(dirname(__FILE__) . '/../../includes/init.php'); 在开头要加入这两句文件才可以访问数据库以 ...