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 ...
随机推荐
- 如何判断JDK是32位还是64位
第一种方法 在CMD窗口中使用java -version 命令进行查看 如果是64位的则会显示 Java HotSpot<TM>64-Bit 字样,32位的则没有类似信息. 注:这是Sun ...
- xslt语法之---运算符号
<xsl:param name="count">12</xsl:param > <xsl:template match="/" ...
- struts2 convention-plugin实现零配置
零配置并不是没有配置,而是通过约定大于配置的方式,大量通过约定来调度页面的跳转而使得配置大大减少.使得Action等配置不必写在Struts.xml中. convention-plugin的约定 1. ...
- CUDA与VS2013安装
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- sqlite使用blob类型存储/访问 结构体
/* open fire host and slora report data database */ int open_report_db(void) { ; char sql[SQL_COMMAN ...
- 实现一个线程安全的Queue队列
使用装饰者模式实现一个线程安全的Queue队列. public class SynchronizedQueue<E> implements Queue<E>, Serializ ...
- JAVA跑马灯实现1
<TextView android:layout_width="wrap_content" android:layout_height=" ...
- PHP 通过随机数获得ASCII 值返回字符。
for($i=0;$i<20;$i++){ $Matrix .= chr(65 + rand(0,26)); }
- oracle 查看用户表数目,表大小,视图数目等
查看当前用户的缺省表空间 SQL>select username,default_tablespace from user_users; 查看当前用户的角色 SQL>select * fr ...
- git代码库的使用
代码库/使用指南 http://learn.zone.jd.com/cmsuser/index.htm 在win7系统下使用TortoiseGit(乌龟git)简单操作Git@OSC http://m ...