原子性

定义:原子性是指在一个操作中cpu不可以在中途暂停然后再调度,即不被中断操作,要不全部执行完成,要不都不执行。就好比转账,从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。2个操作必须全部完成。

关键字:synchronized

1
2
3
4
private long count = 0;
public void calc(){
count++;
}

在上述代码中,将执行以下步骤:

  1. 将count从主存读取到工作内存中的副本
  2. +1运算
  3. 将结果写入工作内存
  4. 将工作内存中的值刷回主存(什么时候刷入由操作系统决定,不确定的)

可见性

定义:当一个线程修改了共享变量的值,其他线程会马上知道这个修改。当其他线程要读取这个变量的时候,最终会去内存中读取,而不是从缓存中读取。

20210311093939

关键字:volatile、synchronized、final

有序性

定义:虚拟机在进行代码编译时,对于那些改变顺序之后不会对最终结果造成影响的代码,虚拟机不一定会按照我们写的代码的顺序来执行,有可能将他们重排序。实际上,对于有些代码进行重排序之后,虽然对变量的值没有造成影响,但有可能会出现线程安全问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 0;
boolean flag = false;

public void write(){
a = 2; //1 //1
flag = true; //2 //4
}


public void multiply(){
if(flag){ //3 //2
int res = a * a; //4 //3
}
}
1
2
3
4
5
6
7
如果按照1234执行,结果为:
a = 2;
res = 4;

如果按照1423执行,结果为:
a = 2;
res = 0;

关键字:volatile、synchronized

volatile本身就包含了禁止指令重排序的语义,而synchronized关键字是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则明确的。

小结

  1. synchronized关键字同时满足以上三种特性,但是volatile关键字不满足原子性。
  2. 在某些情况下,volatile的同步机制的性能确实要优于锁(使用synchronized关键字或java.util.concurrent包里面的锁),因为volatile的总开销要比锁低。
  3. 我们判断使用volatile还是加锁的唯一依据就是volatile的语义能否满足使用的场景(原子性)

参考文档

高并发的三大特性—原子性、有序性、可见性

评论