用户工具


java 内存模型

  • 一个进程有一个内存块(叫主内存,所有变量都定义在这个内存中)
  • 进程下有多个线程,每个线程有自己的工作内存,该内存中所有变量都拷贝自主内存
  • 线程只能与自己的工作内存通信,线程间数据通信必须通过主内存

可见性和原子性

可见性

可见性指一个线程对某个变量更改后,是否对其他线程可见

可见的必要条件

  1. 线程A在自己的工作内存中对变量V做了修改
  2. 把修改后的变量V同步到主内存
  3. 线程B重主内存重新加载变量V (这时线程B才能看到线程A做的修改)

原子性

某个时刻,只允许一个线程修改某个共享变量

final 关键字

final关键字修饰的变量在各个线程间是可见的

  • final关键字修饰的变量是不可变的,所以在各个线程的工作内存中存的副本值都一样,不存在各个线程不一致的问题,所以在各个线程中都是可见的

volatile 关键字

volatile的可见性

volatile执行过程

  1. 每次读取共享变量时,强制从主内存读取最新的副本到工作内存
  2. 在工作内存中修改共享变量
  3. 共享变量修改后,强制刷新回主内存(所以每个线程在访问时候会读到最新值)

volatile 的原子性

  • 虽然每次都能读取到最新值,但是不能保证原子性。
  • 因为volatile关键字允许多个线程同时修改该变量。当多个线程同时修改时,依然会导致丢失更新(如下情况)
      1. 假如在某一时刻线程A同时读到count的值是5,正准备+1的时候,线程切换到B
      2. 线程B读取count的值为5,线程切换到A
      3. 线程A更新count值为6,并写回主内存,切换到线程B
      4. 线程B更新count值为6,并写回主内存 (然而丢失了一次更新)

可见要做到原子性,必须每个时刻只能有一个线程对该变量进行更新

volatile 不能像synchronized做到原子性,但是他的性能相对synchronized较高。那volatile可以在哪些场景下使用呢?当对变量只读,且修改时不依赖原值的情况下可以使用

synchronized 关键字

synchronized既能保证可见性,又能保证原子性

synchronized执行过程

  1. 获得互斥锁(加锁后,只有该线程有权执行,其他线程必须等待)
  2. 清空工作内存
  3. 从主内从拷贝最新副本到工作内存
  4. 执行代码
  5. 将更新后的值刷新回主内存
  6. 释放互斥锁