java 线程干扰, 内存一致性错误(happens-before)
2016-08-02 16:07
691 查看
http://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html http://www.4byte.cn/learning/120106/happens-before-su-jie.html http://www.blogjava.net/syniii/archive/2010/11/18/338381.html
什么是happens-before?
happens-before就是“什么什么一定在什么什么之前运行”,也就是保证顺序性。
因为CPU是可以不按我们写代码的顺序执行内存的存取过程的,也就是指令会乱序或并行运行,
只有上面的happens-before所规定的情况下,才保证顺序性。
如:
Java代码
public class Test {
private int a = 0;
private long b = 0;
public void set() {
a = 1;
b = -1;
}
public void check() {
if (! ((b == 0) || (b == -1 && a == 1))
throw new Exception("check Error!");
}
}
对于set()方法的执行:
1. 编译器可以重新安排语句的执行顺序,这样b就可以在a之前赋值。如果方法是内嵌的(inline),编译器还可以把其它语句重新排序。
2. 处理器可以改变这些语句的机器指令的执行顺序,甚到同时执行这些语句。
3. 存储系统(由于被缓存控制单元控制)也可以重新安排对应存储单元的写操作顺序,这些写操作可能与其他计算和存储操作同时发生。
4. 编译器,处理器和存储系统都可以把这两条语句的机器指令交叉执行。
例如:在一台32位的机器上,可以先写b的高位,然后写a,最后写b的低位,(注:b为long类型,在32位的机器上分高低位存储)
5. 编译器,处理器和存储系统都可以使对应于变量的存储单元一直保留着原来的值,
以某种方式维护相应的值(例如,在CPU的寄存器中)以保证代码正常运行,直到下一个check调用才更新。
...
在单线程(或同步)的情况下,上面的check()永远不会报错,
但非同步多线程运行时却很有可能。
并且,多个CPU之间的缓存也不保证实时同步,
也就是说你刚给一个变量赋值,另一个线程立即获取它的值,可能拿到的却是旧值(或null),
因为两个线程在不同的CPU执行,它们看到的缓存值不一样,
只有在synchronized或volatile或final的性况下才能保证正确性,
很多人用synchronized时只记得有lock的功能,而忘记了线程间的可见性问题。
什么是happens-before?
happens-before就是“什么什么一定在什么什么之前运行”,也就是保证顺序性。
因为CPU是可以不按我们写代码的顺序执行内存的存取过程的,也就是指令会乱序或并行运行,
只有上面的happens-before所规定的情况下,才保证顺序性。
如:
Java代码
public class Test {
private int a = 0;
private long b = 0;
public void set() {
a = 1;
b = -1;
}
public void check() {
if (! ((b == 0) || (b == -1 && a == 1))
throw new Exception("check Error!");
}
}
对于set()方法的执行:
1. 编译器可以重新安排语句的执行顺序,这样b就可以在a之前赋值。如果方法是内嵌的(inline),编译器还可以把其它语句重新排序。
2. 处理器可以改变这些语句的机器指令的执行顺序,甚到同时执行这些语句。
3. 存储系统(由于被缓存控制单元控制)也可以重新安排对应存储单元的写操作顺序,这些写操作可能与其他计算和存储操作同时发生。
4. 编译器,处理器和存储系统都可以把这两条语句的机器指令交叉执行。
例如:在一台32位的机器上,可以先写b的高位,然后写a,最后写b的低位,(注:b为long类型,在32位的机器上分高低位存储)
5. 编译器,处理器和存储系统都可以使对应于变量的存储单元一直保留着原来的值,
以某种方式维护相应的值(例如,在CPU的寄存器中)以保证代码正常运行,直到下一个check调用才更新。
...
在单线程(或同步)的情况下,上面的check()永远不会报错,
但非同步多线程运行时却很有可能。
并且,多个CPU之间的缓存也不保证实时同步,
也就是说你刚给一个变量赋值,另一个线程立即获取它的值,可能拿到的却是旧值(或null),
因为两个线程在不同的CPU执行,它们看到的缓存值不一样,
只有在synchronized或volatile或final的性况下才能保证正确性,
很多人用synchronized时只记得有lock的功能,而忘记了线程间的可见性问题。
相关文章推荐
- Java并发编程番外篇(三)volatile变量、happens-before与内存一致性错误
- 内存一致性错误和线程干扰
- 【翻译八】java-内存一致性错误
- Java 多线程之内存一致性错误
- Java 内存模型之 happens-before
- 【Java并发编程】内存一致性错误
- Java内存 happens-before原则
- 死磕 Java 并发 :Java 内存模型之 happens-before
- The Java™ Tutorials — Concurrency :Memory Consistency Errors 内存一致性错误
- Java并发11:Java内存模型、指令重排、内存屏障、happens-before原则
- Java多线程:volatile变量、happens-before关系及内存一致性
- 学习笔记之Java线程安全杂谈(中)——Java内存模型、happens-before原则和DCL问题
- JVM启动内存错误 java/lang/OutOfMemoryError
- Java线程并发干扰问题及解决方式(锁对象)
- maven:Java heap space内存不足错误的解决方法
- Eclipse出现内存空间不够的错误:Unable to execute dex: Java heap space
- 一,谈谈JAVA线程的运行内存模型【JAVA内存模型】
- soa---java 多线程-线程内存模型
- 秦晓波著的编写高质量代码-改善Java程序的151个建议一书中的线程解释错误.
- 关于“Damage:before normal block..."(内存的使用错误)