关于 volatile 的一个小知识点

volatile 的具体作用和原理可能大家都基本了解了,无非是可见性、禁止指令重排序、主内存、内存屏障等几个关键字,就不赘述了。

本来我也以为 volatile 学到这里就 OK 了,但最近发现了一个小知识点,而网上很多文章都没说到,因此特地写了这篇文章来讨论讨论。

我们都知道 volatile 能保证可见性,但它保证的是谁的可见性呢?是引用,还是对象?假如使用 volatile 来修饰 Object 或者数组,而 Object 或数组的成员被修改了,其它线程能立刻感知到吗?

为了验证这个问题,我专门写了一个测试 demo:

public class VolatileObject {

    public int a;
    public int b;

    public VolatileObject(int a, int b) {
        this.a = a;
        this.b = b;
    }

    private static volatile boolean stop = false;
    private static volatile VolatileObject object = new VolatileObject(1, 100);

    public static void main(String[] args) {
        // 线程 1
        new Thread(() -> {
            while (!stop) {
                System.out.println("[a: " + object.a + "], [b: " + object.b + "]");
            }
        }).start();

        // 线程 2
        new Thread(() -> {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            object.a = 2;
            System.out.println("-----------changed a");
            object.b = 200;
            System.out.println("-----------changed b");
            stop = true;
            System.out.println("-----------stop");
        }).start();
    }

}
复制代码

运行结果:

...
[a: 2], [b: 100]
[a: 2], [b: 100]
[a: 2], [b: 100]
-----------changed a
-----------changed b
-----------stop
[a: 2], [b: 100]
复制代码

可以发现,在线程 2 修改了 object 的成员 b 的值之后,线程 1 读取的仍然是 object 被修改之前的值。

因此,可以得出结论:volatile 修饰的是引用,而不是对象

也就是说,如果引用改变了:

object = null; // 或者指向了另一个对象
复制代码

这种情况下,volatile 是能保证可见性的。

但如果,引用未改变,改变的是对象的值:

object.a = 2;
object.b = 200;
复制代码

这种情况下,volatile 是不保证其它线程能够立刻得知这个修改的。

因此,使用 volatile 修饰对象或者数组的时候要注意,你关心的是引用的改变,还是数据的改变?如果是引用,那么可以继续使用 volatile 没问题;如果是数据,要么再次使用 volatile 修饰对应的数据,要么直接使用 synchronized。

以上就是本文讨论的问题,水平有限,如有错漏,请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值