多线程(四)—— 内存可见性

   多个线程对同一个变量(称为:共享变量)进行操作,但是这多个线程有可能被分配到多个处理器中运行,那么编译器会对代码进行优化,当线程要处理该变量时,多个处理器会将变量从主存复制一份分别存储在自己的存储器中,等到进行完操作后,再赋值回主存。

  这样做的好处是提高了运行的速度,同样优化带来的问题之一是变量可见性——如果线程t1与线程t2分别被安排在了不同的处理器上面,那么t1与t2对于变量A的修改时相互不可见,如果t1给A赋值,然后t2又赋新值,那么t2的操作就将t1的操作覆盖掉了,这样会产生不可预料的结果。因此,需要保证变量的可见性(一个线程对共享变量值的修改,能够及时地被其它线程看到)。

  注意:共享数据的访问权限必须定义为private

  多线程操作共享变量实现可见性过程JVM的内存模型如下:

      

多线程(四)—— 内存可见性

  所有的变量都存储在主内存中每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)。

 JVM模型两条规定

   1、线程对共享变量的所有操作必须在自己的内存中进行,不能直接从主内存中读写

   2、不同线程之间无法直接访问其它线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成

  那么共享变量应该怎样实现可见性呢?  

  比如:线程1对共享变量的修改想要被线程2及时看到,必须经过如下2步操作:
  把工作内存1中的更新过的共享变量刷新到主内存中,再将主内存中最新的共享变量的值更新到2的工作内存中。

  初始值X=0,线程1将X=1,到其他线程X值的更改,如下图的更改过程。

                  

多线程(四)—— 内存可见性

   因此,要实现共享变量的可见性,必须保证两点:
   线程修改后的共享变量值能够及时从工作内存刷新到主内存中;
   其他线程能够及时的把共享变量的最新值从主内存更新到自己的工作内存中。

   在Java语言层面支持的可见性实现原理方式有synchronize和volatile。

备注:

导致共享变量在线程间不可见的原因:
  线程的交叉执行;
  重排序结合线程的交叉执行;
  共享变量更新后的值没有在工作内存与主内存及时更新。

 二、synchronize 

  能够实现代码的原子性(同步)和 内存的可见性。

原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

原子性就像数据库里面的事务一样,他们是一个团队,同生共死。其实理解原子性非常简单,我们看下面一个简单的例子即可:

i = 0;---1 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdsgy.html