【多线程】volatile关键字详解

volatile的作用

volatile主要用于解决可见性有序性的问题,但不保证原子性

  • 可见性:
    • 线程在操作变量时,会将主存中的变量拷贝一份到本地存储;修改有再找时机写回主存(不可控),这样多线程并发时会导致其他线程看到的数据和当前线程不一致
    • 使用volatile关键字修饰变量,可使得每次执行写操作时直接将值刷新到主存中,通过内存屏障使得其他线程本地副本失效;执行读操作时会强制从主存中加载最新的值。
  • 禁止指令重排序
    • JVM和CPU可能会对指令进行重排序优化(单例模式中如果静态变量不使用volatile关键字修饰会有重排序的风险)
    • volatile修饰的变量通过插入内存屏障来禁止编译器和处理器对指令进行重排序,来保证执行符合预期

适用场景

volatile的写操作和读操作都是直接操作主存吗?

写操作:

执行写操作时,使用内存屏障将写入主存的变量在其他线程的副本状态置为失效,然后强制其他线程再要使用该变量时从主存中获取。

读操作:

读操作分两种情况

  • 线程在对volatile变量进行读取时,如果本地副本状态正常,则从本地缓存中读取该变量的值
    image

  • 线程在对volatile变量进行读取时,如果本地副本状态时失效,则从主存中读取该变量的值,刷新到本地缓存
    image

与synchronized的区别

  • synchronized用于实现原子性和互斥访问,同时隐含了可见性和有序性
    • 原子性:synchronized关键字通过锁机制保证同一时间只有一个线程执行临界区代码,保证原子性
    • 可见性和有序性:线程进入synchronized代码块时会从主存加载变量,写入本地内存;退出时会将本地内存刷新到主内存中;通过锁来保证代码块的代码不会被重排序到外部
  • 两者最大的区别
    • volatile修饰的变量所有的线程在变量发生变更后都会从主内存去取。
      synchronized代码块修改的变量(里面多线程共享的变量未被volatile修饰),只有进入synchronized代码的时候才会从主内存中取。
  • 所以多线程编程时如果对于某个变量是多线程的读和写,一定要加上volatile关键字修饰,否则未加锁的读线程可能会读到旧值
posted @ 2025-03-06 00:07  此木|西贝  阅读(257)  评论(0)    收藏  举报