1、明白一个关于Java中主内存和线程工作内存的概念。

     假如一个static修饰的变量,其值会存储在主内存。如果多个线程访问这个变量的话,每个线程都会将变量的值拷贝到自己的工作内存中去,之后的操作就是针对自己拷贝过来的副本进行操作,最后操作完成后写回主内存中。

     对于上面的操作是非原子性的操作,出现多线程的问题

 变量 i=6,线程A和B都对i进行加1操作,期待i为8,但是:

 线程A访问 i,

 线程A进行 i++操作

 线程B访问 i,

 线程B进行 i++操作

 线程A更新i,i为7

 线程B更新i,i为7

 2、对于关键字volatile来说,告诉JVM(Java虚拟机),我们访问被它修饰的变量,不需要创建工作内存的副本,我们直接操作主内存上面的变量,它涉及到多线程的可见性:

对于可见性,Java提供了volatile关键字来保证可见性。

  当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

  而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。

  3. 但是,volatile依然无法保证原子性,在1中所说的情况依然会出现,所以volatile可以保证可见性,不能保证原子性

  4. 那么原子性和可见性有什么区别呢?

    原子性就是一个操作的执行是不能被打断的

    可见性是一个操作的执行结果马上被其他操作所感知,区别于原子性是,不能保证本操作不被打断,只是本操作执行的结果能够被其他操作所感知。