atomicity and volatility 代替synchronized 对象锁 的另一种方法(原子操作+可见性)
2017-06-21 15:34
417 查看
参考文章:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
https://www.ibm.com/developerworks/library/j-jtp06197/index.html
https://tutorials.jenkov.com/java-concurrency/volatile.html
1、atomicity(原子操作):一个操作不中断,一直执行完
对成员变量进行操作。
volatile:就是在原子操作下,保证变量的visible。
2、按照:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
编译和运行时:
1>禁止分配它们到寄存器(registers),保证一个线程写后能马上更新到内存,所有线程都能看见,
2>必须保证volatile变量读之前缓冲区(cpu cache)无效,哪么线程只能在内存读。
原因:有可能编译器重新排序 v=true,x=42,哪么读出的是未改变的值。
所以:编译器看见有volatile变量存在的地方,有cpu缓存,但是读时不让去缓冲读,直接从内存读,不重新排序。
一、功能介绍
1、atomicity :原子操作,也叫lock-free 无锁,即不需要锁操作。
优点:操作不能被thread 调度者中断,一气呵成,比如:正在高考数学,考完才出来吧!
atomicity :对应单cpu ,在多cpu用 visibility代替。
2、比较
目前默认原子操作的变量:primtive types(int,char,byte):原子操作,读、写只需要一条指令即可。
1》返回值 return i;这是一个原子操作。
3、 volatility:对syn对象锁的补充。
a long or double:是64位,一次读,非原子操作,需要分成两个32位来操作,对应两条指令,两条指令中间可以插入其它指令。
(1) 设置成员变量:非volatility
当对一个线程对成员变量进行的an atomic 操作时,就我一个干活线程用,别的干活线程不用,哪么也不需要刷新main memory了(主要目的让别的线程看见新改的值)
(2)设置成员变量:volatility (有波动的意思)
1>实时更新数据
多个干活线程访问同一个成员变量时,必须设置成volatility ,当一个线程改了成员变量值,哪么所有用到这个成员变量的干活线程必须能看见新改的值。
2>volatility 可以让一个long 变量成为原子操作?未测试
本来一个64位的 long是非原子操作。
二、例子: 一看,感觉下面两个方法对成员变量i是原子操作
但是指令“get” 和 "put" 之间,另一个对象也可以修改成员变量的值,所以下面操作非原子。
Atomicity 类,可以new Atomicity(),生成多个对象,并且多个对象都可以操作f1(),f2()方法,有可能存在先执行,同时执行等待的可能。
反编译:
三、不要盲目使用原子的思想
下面例子本想取一个偶数值,但是由于getValue 以为是原子操作,没有设置对象锁。
因此当evenIncrement 执行到一个i++后(奇数)------getValue 取值,出现错误。
1、成员变量 i
2、方法getValue(只有返回值),是一个原子操作
3、方法 evenIncrement 带有对象锁 自增1,两次,
4、干活线程AtomicityTest,
参考文章:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
https://www.ibm.com/developerworks/library/j-jtp06197/index.html
https://tutorials.jenkov.com/java-concurrency/volatile.html
1、atomicity(原子操作):一个操作不中断,一直执行完
对成员变量进行操作。
volatile:就是在原子操作下,保证变量的visible。
2、按照:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
编译和运行时:
1>禁止分配它们到寄存器(registers),保证一个线程写后能马上更新到内存,所有线程都能看见,
2>必须保证volatile变量读之前缓冲区(cpu cache)无效,哪么线程只能在内存读。
class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { //uses x - guaranteed to see 42. } } }1>如果v不是volatile变量,哪么reader()读操作,当v==true,有可能读到x=0。
原因:有可能编译器重新排序 v=true,x=42,哪么读出的是未改变的值。
所以:编译器看见有volatile变量存在的地方,有cpu缓存,但是读时不让去缓冲读,直接从内存读,不重新排序。
一、功能介绍
1、atomicity :原子操作,也叫lock-free 无锁,即不需要锁操作。
优点:操作不能被thread 调度者中断,一气呵成,比如:正在高考数学,考完才出来吧!
atomicity :对应单cpu ,在多cpu用 visibility代替。
2、比较
synchronized:不能保证共享变量前的所有变量数据(非共享数据)一定会存入内存。 如果是共享数据,哪么感觉两个线程基本上会看见新值。 因为这syn对象锁保证只有单独一个线程读数据后,保存到内存,下一个线程才能读,这是syn对象锁的基本功能。 | atomicity,volatile: 编译器或jvm不能重新排序volatil 指令的执行顺序。 |
特殊情况有可能如下: 一个synchronized 线程改变成员变量值后 1》首先应该写入到缓冲中,如果当前干活线程改变值后,值存放在缓中,未向内存写。 2》这时手动删除本window7的缓存, 3》下一个线程执行的话,去内存取,还是以前的值,所以刚刚改的值根本未入内存 感觉只有这种情况下才会出错,一般应该没问题。 | 1>一个线程写入变量后,马上入内存。 2>多个线程读,直接去内存读,所以这种情况数据不存在一致性问题。 但是,如果一个线程写入变量到cache后,未入内存,刚好另一个线程从内存读,又出现一致性问题了。 |
1》返回值 return i;这是一个原子操作。
3、 volatility:对syn对象锁的补充。
a long or double:是64位,一次读,非原子操作,需要分成两个32位来操作,对应两条指令,两条指令中间可以插入其它指令。
(1) 设置成员变量:非volatility
当对一个线程对成员变量进行的an atomic 操作时,就我一个干活线程用,别的干活线程不用,哪么也不需要刷新main memory了(主要目的让别的线程看见新改的值)
(2)设置成员变量:volatility (有波动的意思)
1>实时更新数据
多个干活线程访问同一个成员变量时,必须设置成volatility ,当一个线程改了成员变量值,哪么所有用到这个成员变量的干活线程必须能看见新改的值。
2>volatility 可以让一个long 变量成为原子操作?未测试
本来一个64位的 long是非原子操作。
二、例子: 一看,感觉下面两个方法对成员变量i是原子操作
但是指令“get” 和 "put" 之间,另一个对象也可以修改成员变量的值,所以下面操作非原子。
Atomicity 类,可以new Atomicity(),生成多个对象,并且多个对象都可以操作f1(),f2()方法,有可能存在先执行,同时执行等待的可能。
package concurrency; public class Atomicity { int i; void f1() { i++; } void f2() { i += 3; } } |
void f1(); Code: 0: aload_0 1: dup 2: getfield #2; //取得成员变量i 5: iconst_1 6: iadd 7: putfield #2; //保存成员变量i 10: return void f2(); Code: 0: aload_0 1: dup 2: getfield #2; //Field i:I 5: iconst_3 6: iadd 7: putfield #2; //Field i:I 10: return |
下面例子本想取一个偶数值,但是由于getValue 以为是原子操作,没有设置对象锁。
因此当evenIncrement 执行到一个i++后(奇数)------getValue 取值,出现错误。
1、成员变量 i
2、方法getValue(只有返回值),是一个原子操作
3、方法 evenIncrement 带有对象锁 自增1,两次,
4、干活线程AtomicityTest,
package concurrency; import java.util.concurrent.*; public class AtomicityTest implements Runnable { private int i = 0; public int getValue() { return i; } private synchronized void evenIncrement() { i++; i++; } public void run() { System.out.println("run 开始!"); while (true) evenIncrement(); } public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); AtomicityTest at = new AtomicityTest(); exec.execute(at); System.out.println("main!"); while (true) { System.out.println("main 循环开始!"); int val = at.getValue(); System.out.println("val ="+val); if (val % 2 != 0) { System.out.println(val); System.exit(0); } } } } |
相关文章推荐
- Java多线程编程学习笔记 synchronized的理解 原子操作 actomic compareAndSet
- 锁对象Lock 比使用synchronized 方法和语句可获得的更广泛的锁定操作
- 获取表单对象,得三种方法getElementById(), getElementsByName(), and getElementsByTagName() 和用法
- 创建和销毁对象 第一条:考虑用静态工厂方法代替构造器
- 一张图讲解对象锁和关键字synchronized修饰方法(代码块)
- 操作json数组和json对象,和使用$.post方法
- Atomicity(原子性),visibility(可被观察性),volatility(挥发性)
- 获得对象的另一种方法
- java synchronized关键字的用法以及锁的等级:方法锁、对象锁、类锁
- gcc 原子操作 compare and swap系列
- synchronized,当作用于方法与对象的不同之处
- JavaScript操作JSON的方法总结,JSON字符串转换为JSON对象
- 内存可见性和原子性:Synchronized和Volatile的比较
- Hibernate_操作对象_Session中的refresh()方法与修改事务隔离级别详解
- JavaScript传递对象参数到方法里的另一种方法(对象字面量)
- java多线程----synchronized方法锁能否锁住对象呢?
- CSLA根对象、子对象切换的另一种方法
- 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
- 内存可见性和原子性:Synchronized和Volatile的比较
- js String对象中常用方法小结(字符串操作)