《Java并发编程的艺术》 —3.4 volatile的内存语义

举报
华章计算机 发表于 2019/12/03 15:42:02 2019/12/03
【摘要】 本节书摘来自华章计算机《Java并发编程的艺术》一书中第3章,第3.4.1节,作者是方腾飞 魏鹏 程晓明。

3.4 volatile的内存语义

当声明共享变量为volatile后,对这个变量的读/写将会很特别。为了揭开volatile的神秘面纱,下面将介绍volatile的内存语义及volatile内存语义的实现。

3.4.1 volatile的特性

理解volatile特性的一个好方法是把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步。下面通过具体的示例来说明,示例代码如下。

class VolatileFeaturesExample {

    volatile long vl = 0L;                    // 使用volatile声明64位的long型变量

 

    public void set(long l) {

        vl = l;                             // 单个volatile变量的写

    }

 

    public void getAndIncrement () {

        vl++;                              // 复合(多个)volatile变量的读/写

    }

 

 

    public long get() {

        return vl;                        // 单个volatile变量的读

    }

}

假设有多个线程分别调用上面程序的3个方法,这个程序在语义上和下面程序等价。

class VolatileFeaturesExample {

    long vl = 0L;                                 // 64位的long型普通变量

 

    public synchronized void set(long l) {     // 对单个的普通变量的写用同一个锁同步

        vl = l;

    }

 

    public void getAndIncrement () {            // 普通方法调用

        long temp = get();              // 调用已同步的读方法

        temp += 1L;                         // 普通写操作

        set(temp);                      // 调用已同步的写方法

    }

 

 

    public synchronized long get() {              // 对单个的普通变量的读用同一个锁同步

        return vl;

    }

}

如上面示例程序所示,一个volatile变量的单个读/写操作,与一个普通变量的读/写操作都是使用同一个锁来同步,它们之间的执行效果相同。

锁的happens-before规则保证释放锁和获取锁的两个线程之间的内存可见性,这意味着对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

锁的语义决定了临界区代码的执行具有原子性。这意味着,即使是64位的long型和double型变量,只要它是volatile变量,对该变量的读/写就具有原子性。如果是多个volatile操作或类似于volatile++这种复合操作,这些操作整体上不具有原子性。

简而言之,volatile变量自身具有下列特性。

可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。