java多线程之内存可见性

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

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

e.g:主内存当中有一个变量x,多个线程同时包含有一个x的副本,当某个线程的工作的x值改变的时候要及时地被线程看到。就会一个问题,多个线程之间如何做到拿到的正确的x

+
原理是:
  1. 把工作内存1中更新过的共享变量刷新到主内存中
  2. 将主内存中最新的共享变量的值更新到工作内存2中 
多线程之间使用共享变量并不能保证共享变量的可见性(指令重排序,运行的不确定性),所以在java中有一种方式是使用synchronize(原子性,可见性)
步骤:(关键在于解锁前要把工作内存中的数据刷到主内存中,加锁时,将清空工作内存中的共享变量,加锁后一定要从主内存中重新获取数据)
  1. 获取互斥锁
  2. 清空工作内存
  3. 从主内存拷贝最新副本到本地工作内存中
  4. 执行代码
  5. 将更改后的共享变量刷新到主内存中
  6. 释放锁
Synchronized实际是实现的一种锁的机制,在一段操作和内存进行加锁,同一时刻只有一个线程才能进入锁内,锁内无论怎么重排序执行结果都是一样的。 synchronized同时可以保证可见性

还有一种方式是使用volatile来修饰共享变量
  • 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令
  • 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令
volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫线程将最近的值刷新到主内存。这样任何时刻,不同线程总能看到该变量的最新值。 volatile不能保证volatile变量复合操作的原子性:
synchronized和volatile区别:
  • volatile 不需要加锁,比synchronized更轻量级,不会阻塞线程。
  • 从内存可见性角度,volatile读相当于加锁,volatile写相当于解锁
  • synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性。

指令重排序

重排序:代码书写的顺序与实际执行的顺序不同,指令重排序时编译器或处理器为了提高程序性能能做的优化。

  1. 编译器优化的重排序(编译器优化)
  2. 指令集并行重排序(处理器优化)
  3. 内存系统的重排序(处理器优化) 

你可能感兴趣的:(java多线程之内存可见性)