一、原子性(Atomicity)

定义:即一个操作或者多个操作,要么全部执行并且不被打断,要么就都不执行。

关键字:synchronized

比如:从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。这2个操作必须要具备原子性才能保证不出现一些意外的问题。
综上可知,对变量的写操作不依赖于当前值才是原子级别的,在多线程环境中才可以不用考虑多并发问题。比如:n=n+1、n++ 就不行。n=n+1才是原子级别的,实在没把握就使用synchronized关键字来代替volatile关键字。

二、可见性(Visibility)

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

关键字:volatile、synchronized、final

三、有序性(Ordering)

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

关键字:volatile、synchronized

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

重排序是一种性能上的优化。
如下:因为第一行和第三行有依赖关系,第二行没有任何的依赖关系,所以我们的编译器会认为把第二行重排序后与结果是没有影响的。

int a = 1;                				int b = 1;						
int b = 1;		重排序后代码执行顺序:	int a = 1;
a = a + 1;				  				a = a + 1;

小结:

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