多线程的共享变量的内存不可见性

线程的开销 :
  • 线程的创建和销毁
  • 线程的上下文切换和调度
  • 线程的同步
多线程的内存模型: 线程独有的工作内存(线程缓存用于提高效率)---------所有线程共享的主内存

线程读取在主内存的成员变量(即共享变量)的过程:

  1. 线程的工作内存会去读取主内存的成员变量并保存副本
  2. 线程在工作内存中修改副本
  3. 将修改后的副本的值推送给主空间并改写主空间该成员变量的值
  4. 主空间成员变量修改后的值将不会主动推送给其他线程, 这就造成了线程的工作内存的共享变量的不同步
问题: 各个线程的工作内存不可见
  即 A线程先读取共享变量a, B线程修改了共享变量a后为a`,推送给主内存并改写, 主内存不会推送给A线程,A和B的变量会不同步

解决办法

  • synchroized可以同步值
  • volatile关键字 会使得主内存的共享变量每经过一次改变都会推送给其他的线程, 其他线程会修改其副本

同步值之synchronized和volatile的区别
相同点:
  synchronized 和 volatile都能用来同步共享变量
不同点:
  1. volatile是轻量级的同步策略, 可以修饰基本类型的变量,如int, synchronized是重量级的同步策略,基于对象的同步锁
  2. volatile不具备互斥性, 一个线程访问共享变量 , 其他线程也可以访问共享变量
    synchronized是互斥锁, 具备互斥性, 在被锁的代码块上只能有一个线程访问共享变量

  3. volatile不能保证变量的原子性, 即一组对共享变量的操作不具备事务(要么全部完成,要么全部不完成) 如 i++/i--
即一个线程在进行一组操作中还没完成时, 其他线程也能进入这组操作对共享变量进行修改
而 synchronized则能保证一组对共享变量操作的原子性, 即这组操作全部完成,才能进行下一轮操作
即在被锁的代码块中只能允许一个线程去执行这组操作, 其他需要执行这组操作的线程会进入阻塞状态,等待其完成

总结:

主内存    工作内存
共享变量   副本
工作内存中会主动去拉取主内存的共享变量并创建其副本
工作内存中的副本修改后会推送给主内存改写共享变量
volatile 会使得主内存修改后的共享变量推送其他线程

内存不可见的本质 : 线程之间有互相独立的缓存区, 当多个线程对共享数据进行操作时, 其操作彼此不可见

可以直接理解: 使用volatile之后该共享该变量线程不在工作内存缓存其副本, 所有线程对该变量的操作全是在主内存中完成
即不在存在操作的不可见,所有线程的操作的变量是位于主内存的变量

https://www.cnblogs.com/huangleshu/p/10026222.html
上一篇:Java volatile关键字详解


下一篇:Java并发进阶知识点总结(2)