代码改变世界

浅谈volatile与automicInteger

2019-01-05 19:00  GarfieldEr007  阅读(1581)  评论(0编辑  收藏  举报

在并发环境中有三个因素需要慎重考量,原子性、可见性、有序性。
   voatile 保证了有序性(防止指令冲排序)和变量的内存可见性(每次都强制取主存数据),每次取到volatile变量一定是最新的
   volatile主要用于解决可见性,它修饰变量,相当于对当前语句前后加上了“内存栅栏”。使当前代码之前的代码不会被重排到当前代码之后,当 前代码之后的指令不会被重排到当前代码之前,一定程度保证了有序性。而volatile最主要的作用是使修改volatile修饰的变量值时会使所有线程中的缓存失效,并强制写入公共主存,保证了各个线程的一致。可以看做是轻量级的Synchronized。详情可参看:
automicXXX主要用于解决原子性,有一个很经典的问题:i++是原子性的操作码?答案是不是,它其实是两步操作,一步是取i的值,一步是++。在取值之后如果有另外的线程去修改这个值,那么当前线程的i值就是旧数据,会影响最后的运算结果。使用automicXXX就可以非阻塞、保证原子性的对数据进行增减操作。详情可参看:http://ifeve.com/java-atomic/


volatile原理:
    1.volatile可以保证线程可见性,且提供了一定的有序性,但无法保证原子性。
        1.保证可见性,不保证原子性
2.禁止指令重排序
    2.JVM底层,volatile采用 "内存屏障" 来实现
    
    可见性实现:
             可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值
     synchronize和锁都可以保证可见性。


             线程本身并不直接与主存进行数据交换,而是通过线程的工作内存来完成相应的操作  ---  线程间数据不可见的根本原因!!!
     volatile实现可见性,直接从这方面入手,
        1.修改volatile变量时,会强制将修改后的值刷新到主内存中
2.修改volatile变量后,会导致其他线程工作内存中对应的变量值失效,再读取该变量值时,要重新从主内存中读取


    有序性实现:
             关于重排序:
          编译器重排序:不改变单线程语义的前提下,可以重新安排语句的执行顺序
  处理器重排序:不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
             指令重排序对单线程无影响,但会影响多线程的正确性,
     JVM如何禁止重排序?
           happens-before 原则:保证程序的有序性
---------------------
作者:拉萨之虎2012
来源:CSDN
原文:https://blog.csdn.net/dan1289095756/article/details/80803977
版权声明:本文为博主原创文章,转载请附上博文链接!