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

本文介绍了Java并发编程中volatile关键字的作用,包括保证变量的可见性和防止指令重排。volatile能确保多线程间变量的可见性,避免CPU缓存造成的不一致。同时,volatile提供了Happens Before原则,但不保证原子性。适合在不依赖当前值的写操作且不包含其他变量表达式的场景下使用。
摘要由CSDN通过智能技术生成

那怎么保证程序里一个线程对共享变量的修改能立马被其他线程看到了?这时候有人会说了,加锁呀,前面不就是因为加锁成本太高才使用的 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 修饰的变量,Java 无法保证 JVM 何时会把数据从主存读取到 CPU 缓存,或将数据从 CPU 缓存写入主内存。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值