一 点睛
cpu的读等待,同时指令执行。
cpu乱序执行的根源:https://www.cnblogs.com/liushaodong/p/4777308.html
读指令的同时,可以同时执行不影响其他指令。
而写的同时可以进行合并写。
这样CPU执行就是乱序的。
必须使用 Memory Barrier 来做好指令排序。
volatile 底层就是这么实现的(windows是lock指令)
CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据(慢100倍)),去同时执行另外一条指令,前提是,两条指令没有依赖关系。
写操作也可以合并进行。
二 生活中的例子
三 实战
1 代码
package jmm;
public final class WriteCombiningExt {
private static final int ITERATIONS = Integer.MAX_VALUE;
private static final int ITEMS = 1 << 24;
private static final int MASK = ITEMS - 1;
private static final byte[] array1 = new byte[ITEMS];
private static final byte[] array2 = new byte[ITEMS];
private static final byte[] array3 = new byte[ITEMS];
private static final byte[] array4 = new byte[ITEMS];
private static final byte[] array5 = new byte[ITEMS];
private static final byte[] array6 = new byte[ITEMS];
private static final byte[] array7 = new byte[ITEMS];
private static final byte[] array8 = new byte[ITEMS];
private static final byte[] array9 = new byte[ITEMS];
private static final byte[] array10 = new byte[ITEMS];
private static final byte[] array11 = new byte[ITEMS];
private static final byte[] array12 = new byte[ITEMS];
private static final byte[] array13 = new byte[ITEMS];
private static final byte[] array14 = new byte[ITEMS];
public static void main(final String[] args) {
for (int i = 1; i <= 3; i++) {
System.out.println(i + " SingleLoop duration (ns) = " + runCaseOne());
System.out.println(i + " SplitLoop duration (ns) = " + runCaseTwo());
}
}
// 循环中一次写
public static long runCaseOne() {
long start = System.nanoTime();
int i = ITERATIONS;
while (--i != 0) {
int slot = i & MASK;
byte b = (byte) i;
array1[slot] = b;
array2[slot] = b;
array3[slot] = b;
array4[slot] = b;
array5[slot] = b;
array6[slot] = b;
array7[slot] = b;
array8[slot] = b;
array9[slot] = b;
array10[slot] = b;
array11[slot] = b;
array12[slot] = b;
array13[slot] = b;
array14[slot] = b;
}
return System.nanoTime() - start;
}
// 分两次循环写
public static long runCaseTwo() {
long start = System.nanoTime();
int i = ITERATIONS;
while (--i != 0) {
int slot = i & MASK;
byte b = (byte) i;
array1[slot] = b;
array2[slot] = b;
array3[slot] = b;
array4[slot] = b;
array5[slot] = b;
array6[slot] = b;
array7[slot] = b;
}
i = ITERATIONS;
while (--i != 0) {
int slot = i & MASK;
byte b = (byte) i;
array8[slot] = b;
array9[slot] = b;
array10[slot] = b;
array11[slot] = b;
array12[slot] = b;
array13[slot] = b;
array14[slot] = b;
}
return System.nanoTime() - start;
}
}
2 测试环境
3 测试结果
SingleLoop duration (ns) = 19421047700
SplitLoop duration (ns) = 11710882200
4 说明
分两次循环写的性能优于循环中一次写,这处决于机器的 WC Buffer的个数。
不同机器的WC Buffer个数是不一样的,一般都是4个,但从测试来看,笔者的机器是8个。