硬件内存模型之间的距离。
内存屏障与JVM并发(4)
时间:2011-09-04 infoq 崔康译
隐式内存屏障
显式屏障指令不是序列化内存操作的唯一方式。让我们再看一看Counter类这 个例子。
class Counter{
static int counter = 0;
public static void main(String[] _){
for(int i = 0; i < 100000; i++)
inc();
}
static synchronized void inc(){ counter += 1; }
}
Counter类执行了一个典型的读-修改-写的操作。静态counter字段不是 volatile的,因为所有三个操作必须要原子可见的。因此,inc 方法是 synchronized修饰的。我们可以采用下面的命令编译Counter类并查看生成的汇编 指令。Java内存模型确保了 synchronized区域的退出和volatile内存操作都是相 同的可见性,因此我们应该预料到会有另一个内存屏障。
$ java -XX:+UnlockDiagnosticVMOptions - XX:PrintAssemblyOptions=hsdis-print-bytes -XX:-UseBiasedLocking - XX:CompileCommand=print,Counter.inc Counter
1 0x04d5eda7: push %ebp ;...55
2 0x04d5eda8: mov %esp,%ebp ;...8bec
3 0x04d5edaa: sub $0x28,%esp ;...83ec28
4 0x04d5edad: mov $0x95ba5408,%esi ;...be0854ba 95
5 0x04d5edb2: lea 0x10(%esp),%edi ;...8d7c2410
6 0x04d5edb6: mov %esi,0x4(%edi) ;...897704
7 0x04d5edb9: mov (%esi),%eax ;...8b06
8 0x04d5edbb: or $0x1,%eax ;...83c801
9 0x04d5edbe: mov %eax,(%edi) ;...8907
10 0x04d5edc0: lock cmpxchg %edi,(%esi) ;...f00fb13e
11 0x04d5edc4: je 0x04d5edda ;...0f841000 0000
12 0x04d5edca: sub %esp,%eax ;...2bc4
13 0x04d5edcc: and $0xfffff003,%eax ;...81e003f0 ffff
14 0x04d5edd2: mov %eax,(%edi) ;...8907
15 0x04d5edd4: jne 0x04d5ee11 ;...0f853700 0000
16 0x04d5edda: mov $0x95ba52b8,%eax ;...b8b852ba 95
17 0x04d5eddf: mov 0x148(%eax),%esi ;...8bb04801 0000
18 0x04d5ede5: inc %esi ;...46
19 0x04d5ede6: mov %esi,0x148(%eax) ;...89b04801 0000
20 0x04d5edec: lea 0x10(%esp),%eax ;...8d442410
21 0x04d5edf0: mov (%eax),%esi ;...8b30
22 0x04d5edf2: test %esi,%esi ;...85f6
23 0x04d5edf4: je 0x04d5ee07 ;...0f840d00 0000
24 0x04d5edfa: mov 0x4(%eax),%edi ;...8b7804
25 0x04d5edfd: lock cmpxchg %esi,(%edi) ;...f00fb137
26 0x04d5ee01: jne 0x04d5ee1f ;...0f851800 0000
27 0x04d5ee07: mov %ebp,%esp ;...8be5
28 0x04d5ee09: pop %ebp ;...5d
内存屏障与JVM并发(5)
时间:2011-09-04 infoq 崔康译
不出意外,synchronized生成的指令数量比volatile多。第18行做了一次增操 作,但是JVM没有显式插入内存屏障。相反,JVM 通过在 第10行和第25行cmpxchg 的lock前缀一石二鸟。cmpxchg的语义超越了本文的范畴。lock cmpxchg不仅原子 性执行写操作,也会刷新等待的读写操作。写操作现在将在所有后续内存操作之 前完成。如果我们通过 java.util.concurrent.atomic.AtomicInteger 重构和运 行Counter,将看到同样的手段。
import java.util.concurrent.ato
|