【多线程】Volatile 线程间变量可见

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wrs120/article/details/90581073



1. 线程间如何共享数据

  使用全局变量或共享对象

2. 线程间变量为什么不可见

  归根原因是由Java内存模型引起的,Java内存模型及操作规范:

  1. 共享变量必须存放在工作内存中
  2. 线程有自己的工作内存, 线程只可操作自己的工作内存
  3. 线程要想操作共享变量,需要从主内存中读取到工作内存,改变值后从工作内存同步到主内存中

  根据上面描述,会出现这么一个问题:线程1已经从主内存读取变量a=1到工作内存中去了,但是在更改a=a+1后未更新到主内存之前,线程2又从主内存中读取了变量a=1,此时想想必然会引起数据不一致

主内存和工作内存之间交互遵从同步交互协议,规定了8中原子操作:

  1. lock锁定:将主内存中的变量锁定,为一个线程所独占
  2. unlock解锁:将lock假的锁定接触,此时其他线程有机会访问此变量
  3. read读取:作用于主内存变量,将主内存中的变量读取到工作内存当中去
  4. load载入:作用于工作内存变量,将read读取到的值保存到工作内存中的变量副本中
  5. use使用:作用于工作内存变量,将值传递给线程的代码执行引擎
  6. assign赋值:作用于工作内存变量,将执行引擎处理返回的值重新赋值给变量副本
  7. store存储:作用于工作内存变量,将变量副本的值传递给主内存中
  8. write写入:作用于主内存变量,将store传送过来的值写入到主内存的共享变量中

注意: 每一步是原子操作,但是这8不不是一个原子操作


3.如何使线程间变量可见

3.1 final变量

  变量本来就是不可改变的,不存在改变,所以不同线程间看到的数据永远一样

3.2synchronized

synchronized语义规范:

  1. 进入同步块之前,先清空工作内存中的共享变量,从主内存中重新加载
  2. 解锁前必须把修改的共享变量同步回主内存

synchronized是如何做到线程安全的:

  1. 锁机制保护共享资源,只有获得锁的线程才可操作共享资源
  2. synchronized语义规范保证了修改的共享资源后,会同步回主内存,做到了线程安全

综上:synchronized既实现了互斥性,也实现了可见性

3.3 volatile

使用场景

  1. 通过共享变量控制其它线程
  2. 加volatile修饰的变量所在的块不会进行指令重排优化(防止指令重排后,会出现抛空指针异常)

4. synchronzied与volatile比较

  volatile 使用简单,性能也好,但是由于上面提到的同步交互协议中的8不操作不是一个整体的原子操作,会出现数据不一致问题,所以如果要保证数据的可见性和一致性,就要用synchronzied了

猜你喜欢

转载自blog.csdn.net/wrs120/article/details/90581073
今日推荐