并发编程艺术:volatile关键字

版权声明:本文为博主原创文章,转载请注明原文链接 https://blog.csdn.net/qq_36922927/article/details/83821737

定义:

java语言规范第三版:

java编程计语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排它锁单独获取这个变量。

java提供了volatile关键字,在某些情况下比锁更加方便。如果一个字段(变量)被volatile修饰,java线程内存模型确保所有线程看到这个变量值是一样的。

   在x86处理器下通过工具获取JIT编译器生成的汇编指令来查看对volatile进行写操作时,cpu会做什么事情。

java代码:

instance =new Singleton();//instance是volatile变量

对应的汇编代码:

0x01a3de1d:movb $x0,0x1104800(%esi);

0x0xa3de24: lock add1 $0x0,(%esp);

Lock前缀的指令在多核处理器下会引发两件事:

  • 将当前处理器缓存行的数据写回到系统内存。(注:缓存行是指cpu高速缓存中可以分配的最小存储单元。处理器填写缓存    行时会加载整个缓存行)
  • 这个写回内存的操作会使在其他cpu里缓存了该内存地址的数据无效(如果其他处理器对这个数据进行修改操作时,会重新从系统内存把数据读取到处理器缓存里)。

实现原理:

  1. Lock前缀指令会处理器缓存回写到内存
  2. 一个处理器的缓存回写到内存会导致其他处理器的缓存无效

volatile的使用优化:

jdk1.7并发包新增一个队列集合类LinkedTransferQueue,它在使用volatile变量时,通过追加字节的方式来优化队列出队和入队的性能。

为什么追加字节(64)可以优化性能?

对于英特尔酷睿i7、酷睿、Atom和NetVurs等处理器的L1,L2或L3缓存高速缓存行是64个字节宽,不支持部分填充缓存行,而一个引用变量占4个字节,就有可能导致多个应用变量一起填充到同一个缓存行中,对缓存行加锁,这样会使得队列的头结点和尾节点可能出现在同一个缓存行中,而队列的入队与出队操作时在不断的修改头结点和尾节点,就可能导致头结点和为节点同时锁定,多处理器下严重影响性能。

以下情况:使用volatile变量是不应该追加到64字节:

  • 缓存行宽度不是64字节(如P6系列和奔腾处理器,L1,L2是32字节宽)
  • 共享变量不会被频繁的写,不频繁写,那么缓存行被锁定的几率很小

猜你喜欢

转载自blog.csdn.net/qq_36922927/article/details/83821737