• Java并发编程--变量可见性、避免指令重排,还得是用它


    那怎么保证程序里一个线程对共享变量的修改能立马被其他线程看到了?这时候有人会说了,加锁呀,前面不就是因为加锁成本太高才使用的 ThreadLocal的吗?怎么又说回去了?

    其实CPU每个核心也都是有缓存的,今天要讲的volatile能保证变量在多线程间的可见性,本文我们会对变量可见性、指令重排、Happens Before 原则以及 Volatile 对这些特性提供的支持和在程序里的使用进行讲解,本文大纲如下:

    变量的可见性

    一个线程对共享变量的修改,另外一个线程能够立刻看到,称为变量的可见性。

    在单核系统中,所有的线程都是在一颗 CPU 上执行,CPU 缓存与内存的数据一致性容易解决。但是多核系统中,每颗 CPU 都有自己的缓存,这时 CPU 缓存与内存的数据一致性就没那么容易解决了,当多个线程在不同的 CPU 上执行时,这些线程操作的是不同的 CPU 缓存。

    比如下图中,线程 A 操作的是 CPU-1 上的缓存,而线程 B 操作的是 CPU-2 上的缓存,很明显,这个时候线程 A 对变量 V 的操作对于线程 B 而言不具备可见性。

    Java 里可以使用 volatile 关键字修饰成员变量,来保证成员在线程间的可见性。读取 volatile 修饰的变量时,线程将不会从所在CPU的缓存,而是直接从系统的主存中读取变量值。同理,向一个 volatile 修饰的变量写入值的时候,也是直接写入到主存。

    下面我们再来看一下,当不使用 volatile 时,多线程使用共享变量时的可见性问题。

    Java 变量的可见性问题

    Java 的 volatile 关键字能够保证变量更改的跨线程可见,在一个多线程应用程序中,为了提高性能,线程会把变量从主存拷贝到线程所在CPU信息的缓存上再操作。如果程序运行在多核机器上,多个线程可能会运行在不同的CPU 上,也就意味着不同的线程可能会把变量拷贝到不同的 CPU 缓存上。

    因为CPU缓存的读写速度远高于主存,所以线程会把数据从主存读到 CPU 缓存,数据的更新也是是先更新CPU 缓存中的副本,再刷回主存,除非有(汇编指令)强制要求否则不会每次更新都把数据刷回主存。

    对于非 volatile 修

  • 相关阅读:
    2022年上半年系统分析师上午真题及答案解析
    `AllocConsole` 函数 通过控制台实时看printf日志
    java图形验证码到底是怎么生成的?
    (Matalb分类预测)GWO-BP灰狼算法优化BP神经网络的多维分类预测
    java泛型
    星环科技重磅推出数据要素流通平台Transwarp Navier,助力企业实现隐私保护下的数据安全流通与协作
    C# 多线程造成CPU占用率高
    Java开发面试--Redis专区
    [附源码]计算机毕业设计JAVA校园期刊网络投稿系统
    怎么把文件全部重命名并排序递增
  • 原文地址:https://blog.csdn.net/Trouvailless/article/details/128110641