可见性的概念

一个线程对共享变量值的修改,能够及时地被其他线程看到

共享变量值:如果一个变量在多个线程的工作内存中都使用,存在副本,那么这个变量就是这几个线程的共享变量

两条重要规定:

  1. 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写
  2. 不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值得传递需要通过主内存来完成

JMM(Java Memory Model)

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

共享变量可见性实现原理

线程1把工作内存1中更新过的共享变量刷新到主内存中,主内存把最新的共享变量的值更新到工作内存2中,线程2就能及时看到线程1的修改


synchronize实现可见性

  1. JMM关于synchronize的两条规定

    线程解锁前,必须把共享变量的最新值刷新到主内存中
    线程加锁是,将清空工作内存中共享变量的值,从而使用共享内存时,需要从主内存中重新读取最新的值(加锁和解锁需要同一把锁)

  2. 重排序 as-if-serial

volatile实现可见性

  1. volatile关键字:

    能够保证volatile变量的可见性
    不能保证volatile变量复合操作的原子性

  2. volatile如何实现内存可见性

    通过加入内存屏障和禁止重排序优化来实现
    对变量执行写操作时,会在写操作后加入一条store屏障指令
    volatile 变量执行度操作时,会在读操作前加入一条load屏障指令

  3. volatile不能保证原子性

    当a线程的工作变量已经读过变量的值后,即使b线程改变变量的值,并store到内存中,也不会触发a线程load,因为a线程读取时已经load过了。

  4. 保证变量自增操作的原子性

    使用synchronize关键字
    使用ReentrantLock(java.until.concurrent.locks)
    使用AtomicInterger
    (vava.util.concurrent.atomic)

  5. volatile适用场合
    同时满足:
  • 对变量的写入操作不依赖其当前值,

    不满足:number++,count=count*5等
    满足:boolean变量,记录温度变化的变量等

  • 该变量没有包含在具有其他变量的不变式中

    不满足:不变式low<up


final也可以保证内存可见性


synchronize 和 volatile 比较

volatile不需要加锁,不会阻塞线程
从内存可见性角度讲volatile读相当于加锁,volatile写相当于解锁
synchronize既可以保证可见性和原子性


coding个人博客链接

参考资料-视频

 posted on 2018-07-29 15:08  cosyfish  阅读(109)  评论(0编辑  收藏  举报