关于volatile不具备原子性

volatile可见性和禁止指令重排序这里就不再赘述,主要是讨论一下为什么volatile修饰的变量不能够保证原子性,最常见的就是volatile变量的自增测试

public class VolatileTest {

    public static volatile int race = 0;

    public static void increase() {
        race++;
    }

    private static final int THREADS_COUNT = 20;

    public static void main(String[] args) {
        Thread[] threads = new Thread[THREADS_COUNT];
        for (int i = 0; i < THREADS_COUNT; i++) {
            threads[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10000; i++) {
                        increase();
                    }
                }
            });
            threads[i].start();
        }

        // 等待所有累加线程都结束
        while (Thread.activeCount() > 1)
            Thread.yield();

        System.out.println(race);
    }
}

如上所示,自增结束后race的值并不是200000,主要是因为race的自增操作是非原子的。查看反汇编生成的字节码文件,如下所示

  public static void increase();
    Code:
       0: getstatic     #2                  // Field race:I
       3: iconst_1
       4: iadd
       5: putstatic     #2                  // Field race:I
       8: return

我们可以看到,对于increase函数,一共会生成5条字节码指令,而对于其中的race++操作,对应于前4条指令,即得到race的值,将race值+1,再将race的值同步会内存中。volatile可以保证可见性,即我们获得的race值是主内存中最新的,但是当我们执行自增操作的时候,并不能保证现在没有其他线程对volatile的变量执行自增操作,其他线程可能已经将race的值变大了,此时操作站顶的值就成了过期的数据,所以最后的结果是不准确的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 此文章出自:<a href="http://www.cnblogs.com/dolphin0520/p/39203...
    zlb阅读 659评论 0 6
  • 第6章类文件结构 6.1 概述 6.2 无关性基石 6.3 Class类文件的结构 java虚拟机不和包括java...
    kennethan阅读 1,001评论 0 2
  • 除了充分利用计算机处理器的能力外,一个服务端同时对多个客户端提供服务则是另一个更具体的并发应用场景。衡量一个服务性...
    胡二囧阅读 1,403评论 0 12
  • volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在...
    传奇内服号阅读 512评论 0 2
  • 每次打开手机 就得进简书巡一圈 欣赏 点赞 喜欢 点个遍 点一圈 再一圈 累了歇 歇了点 只要眼睛不打架 脖颈挺一...
    旖旎i阅读 95评论 10 17