原子性(Atomicity)

概念:

  • 对基本数据类型的读取赋值操作是原子性操作

分析代码:

i = 2;		\\1
j = i;		\\2
i++;		\\3
i = i + 1;	\\4
  • 原子性操作:
  • 1 . 读取操作
  • 非原子操作
  • 2、3、4
  • 对于2:先读取i,在写入j
  • 对于3:点读厚些
  • 对于4:同上

可见性(Visibility)

  • Java就是利用 volatile 来提供可见性的,当一个变量被 volatile

有序性(Ordering)

  • JMM是允许编译器和处理器对指令重排序的。
  • 但是规定了 as-if-serial

比如下面的程序段

int a = 0;
boolean flag = false;

public void write(){
	a = 2;				\\1
	flag = true;		\\2
}
public void multify(){
	if (flag)			\\3
		int ret = a * a;\\4
}

分析:

  • 若两线程A、B执行上面的代码,A先执行 write(),B在执行 multify(), 最后 ret == 4
  • write 方法里的 1和 2做了重排序,线程 1先对 flag 赋值为 true,随后执行到线程 2, ret 直接计算出结果,再到线程 1, -这时候 a

解决:

  • 这时候可以为 flag 加上 volatile 关键字,禁止重排序,可以确保程序的“有序性”,也可以上重量级的 synchronizedLock

JMM具备一些先天的有序性,即不需要通过任何手段就可以保证的有序性

happens-before

以下是定义的规则

1. 程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作

2. 监视器锁规则:对一个线程的解锁,happens-before于随后对这个线程的加锁

3. volatile变量规则:对一个volatile域的写,happens-before于后续对这个volatile域的读

4. 传递性:如果A happens-before B ,且 B happens-before C, 那么 A happens-before C

5. start()规则:如果线程A执行操作ThreadBstart()(启动线程B) , 那么A线程的

6. ThreadBstart()happens-before 于B中的任意操作

7. join()原则:如果A执行ThreadB.join()并且成功返回,
那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。

8. interrupt()原则:对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,
可以通过Thread.interrupted()方法检测是否有中断发生.

9. finalize()原则:一个对象的初始化完成先行发生于它的finalize()方法的开始

续:volatile关键字如何满足并发编程的三大特性的?