线程可见性

谈到多线程,天然就扯到数据争用,也就天然转到对线程可见性的学习。多线程

关键字

可见性:指的就是一个线程对共享变量的修改,可以及时被其余线程看到。性能

共享变量:若是一个变量在多个线程的工做内存中都存在副本,那么这个变量就是这几个线程的共享变量。学习

重排序:代码书写的顺序和实际执行的顺序可能不一样,指令重排序是编译器或处理器为了提升程序性能而作的优化优化

  • 编译器优化的重排序
  • 指令集并行重排序
  • 内存系统重排序

as-if-serial 指的是,不管如何重排序,程序执行的结果应该与代码顺序执行的结果一致。 Java编译器、运行时和处理器都会保证Java在单线程下遵循as-if-serial语义线程

Java内存模型(Java Memory Model):描述了Java程序中各类变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。排序

  • 全部的变量都存储在主内存中
  • 每一个线程都有本身独立的工做内存,里面保存该线程使用到的变量的副本
  • 线程对共享变量的全部操做,都必须在本身的工做内存中进行,不能直接从主内存中读写
  • 不一样线程之间没法直接访问其余线程工做内存中的变量,线程简变量的传递须要经过主内存来实现

JMM

致使共享变量在线程间不可见的缘由

  • 线程的交叉执行
  • 重排序结合线程交叉执行
  • 共享变量共享后的值没能在工做内存和主内存之间即便更新

要实现共享变量的可见性,必须保证两点

  • 线程修改后的共享变量值可以及时从工做内存刷新到主内存
  • 其余线程能及时把共享变量的最新值从主内存更新到本身的工做内存中 Java从语言层面支持的可见性实现方式
  • synchronized
  • volatile

synchronized

synchronized用于实现原子性(同步)和可见性。 JMM关于synchronized的两条规定图片

  • 线程解锁前,必须把共享变量的最新值刷新到主内存中
  • 线程加锁前,将清空工做内存中共享变量的值,从而使用共享变量时须要从主内存中从新读取最新的值。(注意:加锁和解锁必须是同一把锁) 因而可知,线程解锁前对共享变量的修改在下次加锁时对其余线程是可见的。而synchronized的原子性,也就是锁,保证了线程不会在共享变量交叉执行,从而避免了可见性的问题。

volatile

  • 可以保证volatile变量的可见性
  • 不能保证volatile变量复合操做的原子性 深刻来讲,volatile经过加入内存屏障和禁止重排序优化来实现可见性
  • 写操做时,会在写操做以后加入一条store屏障指令
  • 读操做时,虎仔读操做以后加入一条load屏障指令 volatile变量的每次读写,都必须向主内存提交或更新,这样便实现了可见性。复合操做指的是num++这样的操做,先+1后赋值,若是线程交叉执行,颇有可能就会出现未可见的问题。 使用场合
  • 对变量的写入操做并不依赖其当前值:boolean
  • 改变量没有包含在具备其余变量的不变式中:不知足 low<up
相关文章
相关标签/搜索