写点什么

volatile 关键字需要知道的几点

用户头像
lich0079
关注
发布于: 2021 年 04 月 18 日

本文作者 https://github.com/lich0079 转载请注明


可见性

多核执行多线程的情况下,每个 core 读取变量不是直接从内存读,而是从 L1, L2 ...cache 读,所以你在一个 core 中的 write 不一定会被其他 core 马上观测到。


解决这个的办法就是 volatile 关键字,加上它修饰后,变量在一个 core 中做了修改,会导致其他 core 的缓存立即失效,这样就会从内存中读出最新的值,保证了可见性。


False sharing

volatile 导致其他 core 缓存失效会带来一个问题。假设 2 个 volatile 变量位于一个缓存单元中(cache line,通常 64 字节),那么一个 core 一直修改变量 A,另一个 core 在使用变量 B,A 的不断更新导致在另一个 core 中处于同一个 cache line 中的 B 也会需要一直去内存拉最新的值,即使另一个完全不关心 A 的值。


解决这个问题的方法就是 Padding,把 volatile 关键字的周围用其他的值来填充,保证 volatile 不会和其他的 volatile 共享一个 cache line

```

class LhsPadding{    protected long p1, p2, p3, p4, p5, p6, p7;}
class Value extends LhsPadding{ protected volatile long value;}
class RhsPadding extends Value{ protected long p9, p10, p11, p12, p13, p14, p15;}public class Sequence extends RhsPadding{ public long get() { return value; }}
复制代码

```


Lazyset


加了 volatile 的变量可以保证对它的修改的可见性,但这种保证也是有性能的代价的。那么对一个 volatile 变量我可不可以有时候不需要它的可见性保证来提升性能呢?


答案就是 sun.misc.Unsafe


```

does not guarantee immediate visibility of the store to other threads. This method is generally only useful if the underlying field is a Java volatile (or if an array cell, one that is otherwise only accessed using volatile accesses).
public native void putOrderedLong(Object o, long offset, long x);
复制代码

```

用法如下, 注意里面对 value 的 set 是有 volatile 和 non volatile 2 个版本,分别针对性能和可见性的场合。


```

package com.lmax.disrupto;
public class Sequence extends RhsPadding{ static final long INITIAL_VALUE = -1L; private static final Unsafe UNSAFE; private static final long VALUE_OFFSET;
static { UNSAFE = Util.getUnsafe(); try { VALUE_OFFSET = UNSAFE.objectFieldOffset(Value.class.getDeclaredField("value")); } catch (final Exception e) { throw new RuntimeException(e); } }
/** * Perform an ordered write of this sequence. The intent is * a Store/Store barrier between this write and any previous * store. * * @param value The new value for the sequence. */ public void set(final long value) { UNSAFE.putOrderedLong(this, VALUE_OFFSET, value); }
/** * Performs a volatile write of this sequence. The intent is * a Store/Store barrier between this write and any previous * write and a Store/Load barrier between this write and any * subsequent volatile read. * * @param value The new value for the sequence. */ public void setVolatile(final long value) { UNSAFE.putLongVolatile(this, VALUE_OFFSET, value); }}
复制代码

```


本文作者 https://github.com/lich0079 转载请注明

发布于: 2021 年 04 月 18 日阅读数: 27
用户头像

lich0079

关注

还未添加个人签名 2018.09.17 加入

https://github.com/lich0079

评论

发布
暂无评论
volatile 关键字需要知道的几点