volatile 靠的是内存屏障
synchronized 关键字底层是通过 monitorenter 和 monitorexit 实现的,而这两个指令又是通过 lock 和 unlokc 实现的
而lock和unlock在Java内存模型中是必须满足下面四条规则的:
规则一
:一个变量同一时刻只允许一个线程对其进行lock操作,但lock操作可以被同一个线程执行多次,多次执行后,只有执行相同次数的unlock操作,变量才能被解锁。规则二
:如果一个变量没有执行lock操作,将会情况工作内存中此变量的值,在执行引擎使用这个变量前,需要重新load 和 assign 操作初始化变量的值规则三
:如果一个变量没有被lock锁定,则不允许使用unlock操作,也不允许unlock一个其他线程锁定的变量规则四
:对一个变量执行unlock操作之前,必须先把此变量同步回主内存中,即执行store 和write操作。原子性: 通过规则一
,我们知道对于lock和unlock之间的代码,同一时刻只允许一个线程操作。所以保证了原子性。
可见性: 通过规则一、二、四
,可以得出,每次lock和unlock时,都会从内存加载变量或把变量刷新回内存,而lock和unlock之间的变量是不会被其他线程修改的(规则一:同一时刻只允许一个线程
)。所以保证了可见性
有序性: 通过规则一、三
,我们知道所有对变量的加锁都要排队进行,且其它线程不允许解锁当前线程锁定的对象,所以,synchronized是具有有序性的。