该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-04-22
最后修改:2010-04-22
作者 Dennis Byrne 译者 崔康 发布于 2010年4月21日 上午1时10分 // code run by first thread // code run by second thread 1 intentFirst = true; intentSecond = true; 2 3 while (intentSecond) while (intentFirst) // volatile read 4 if (turn != 0) { if (turn != 1) { // volatile read 5 intentFirst = false; intentSecond = false; 6 while (turn != 0) {} while (turn != 1) {} 7 intentFirst = true; intentSecond = true; 8 } } 9 10 criticalSection(); criticalSection(); 11 12 turn = 1; turn = 0; // volatile write 13 intentFirst = false; intentSecond = false; // volatile write 1 0x2000000001de819c: adds r37=597,r36;; ;...84112554 2 0x2000000001de81a0: ld1.acq r38=[r37];; ;...0b30014a a010 3 0x2000000001de81a6: nop.m 0x0 ;...00000002 00c0 4 0x2000000001de81ac: sxt1 r38=r38;; ;...00513004 5 0x2000000001de81b0: cmp4.eq p0,p6=0,r38 ;...1100004c 8639 6 0x2000000001de81b6: nop.i 0x0 ;...00000002 0003 7 0x2000000001de81bc: br.cond.dpnt.many 0x2000000001de8220;; 1 0x2000000001de81c0: adds r37=592,r36;; ;...0b284149 0421 2 0x2000000001de81c6: st4.rel [r37]=r39 ;...00389560 2380 3 0x2000000001de81cc: adds r36=596,r36;; ;...84112544 4 0x2000000001de81d0: st1.rel [r36]=r0 ;...09000048 a011 5 0x2000000001de81d6: mf ;...00000044 0000 6 0x2000000001de81dc: nop.i 0x0;; ;...00040000 7 0x2000000001de81e0: mov r12=r33 ;...00600042 0021 8 0x2000000001de81e6: mov.ret b0=r35,0x2000000001de81e0 9 0x2000000001de81ec: mov.i ar.pfs=r34 ;...00aa0220 10 0x2000000001de81f0: mov r6=r32 ;...09300040 0021 1 0x03f8340c: push %ebp ;...55 2 0x03f8340d: sub $0x8,%esp ;...81ec0800 0000 3 0x03f83413: mov $0x14c,%edi ;...bf4c0100 00 4 0x03f83418: movb $0x1,-0x505a72f0(%edi) ;...c687108d a5af01 5 0x03f8341f: mfence ;...0faef0 6 0x03f83422: mov $0x148,%ebp ;...bd480100 00 7 0x03f83427: mov $0x14d,%edx ;...ba4d0100 00 8 0x03f8342c: movsbl -0x505a72f0(%edx),%ebx ;...0fbe9a10 8da5af 9 0x03f83433: test %ebx,%ebx ;...85db 10 0x03f83435: jne 0x03f83460 ;...7529 11 0x03f83437: movl $0x1,-0x505a72f0(%ebp) ;...c785108d a5af01 12 0x03f83441: movb $0x0,-0x505a72f0(%edi) ;...c687108d a5af00 13 0x03f83448: mfence ;...0faef0 14 0x03f8344b: add $0x8,%esp ;...83c408 15 0x03f8344e: pop %ebp ;...5d 1 0xfb8ecc84: ldub [ %l1 + 0x155 ], %l3 ;...e60c6155 2 0xfb8ecc88: cmp %l3, 0 ;...80a4e000 3 0xfb8ecc8c: bne,pn %icc, 0xfb8eccb0 ;...12400009 4 0xfb8ecc90: nop ;...01000000 5 0xfb8ecc94: st %l0, [ %l1 + 0x150 ] ;...e0246150 6 0xfb8ecc98: clrb [ %l1 + 0x154 ] ;...c02c6154 7 0xfb8ecc9c: membar #StoreLoad ;...8143e002 8 0xfb8ecca0: sethi %hi(0xff3fc000), %l0 ;...213fcff0 9 0xfb8ecca4: ld [ %l0 ], %g0 ;...c0042000 10 0xfb8ecca8: ret ;...81c7e008 11 0xfb8eccac: restore ;...81e80000 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; } } 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 不出意外,synchronized生成的指令数量比volatile多。第18行做了一次增操作,但是JVM没有显式插入内存屏障。相反,JVM通过在 第10行和第25行cmpxchg的lock前缀一石二鸟。cmpxchg的语义超越了本文的范畴。lock cmpxchg不仅原子性执行写操作,也会刷新等待的读写操作。写操作现在将在所有后续内存操作之前完成。如果我们通过 java.util.concurrent.atomic.AtomicInteger 重构和运行Counter,将看到同样的手段。 import java.util.concurrent.atomic.AtomicInteger; class Counter{ static AtomicInteger counter = new AtomicInteger(0); public static void main(String[] args){ for(int i = 0; i < 1000000; i++) counter.incrementAndGet(); } }
$ java -XX:+UnlockDiagnosticVMOptions -XX:PrintAssemblyOptions=hsdis-print-bytes -XX:CompileCommand=print,*AtomicInteger.incrementAndGet Counter 1 0x024451f7: push %ebp ;...55 2 0x024451f8: mov %esp,%ebp ;...8bec 3 0x024451fa: sub $0x38,%esp ;...83ec38 4 0x024451fd: jmp 0x0244520a ;...e9080000 00 5 0x02445202: xchg %ax,%ax ;...6690 6 0x02445204: test %eax,0xb771e100 ;...850500e1 71b7 7 0x0244520a: mov 0x8(%ecx),%eax ;...8b4108 8 0x0244520d: mov %eax,%esi ;...8bf0 9 0x0244520f: inc %esi ;...46 10 0x02445210: mov $0x9a3f03d0,%edi ;...bfd0033f 9a 11 0x02445215: mov 0x160(%edi),%edi ;...8bbf6001 0000 12 0x0244521b: mov %ecx,%edi ;...8bf9 13 0x0244521d: add $0x8,%edi ;...83c708 14 0x02445220: lock cmpxchg %esi,(%edi) ;...f00fb137 15 0x02445224: mov $0x1,%eax ;...b8010000 00 16 0x02445229: je 0x02445234 ;...0f840500 0000 17 0x0244522f: mov $0x0,%eax ;...b8000000 00 18 0x02445234: cmp $0x0,%eax ;...83f800 19 0x02445237: je 0x02445204 ;...74cb 20 0x02445239: mov %esi,%eax ;...8bc6 21 0x0244523b: mov %ebp,%esp ;...8be5 22 0x0244523d: pop %ebp ;...5d 我们又一次在第14行看到了带有lock前缀的写操作。这确保了变量的新值(写操作)会在其他所有后续内存操作之前完成。 1 0x03f83422: mov $0x148,%ebp ;...bd480100 00 2 0x03f83427: mov $0x14d,%edx ;...ba4d0100 00 3 0x03f8342c: movsbl -0x505a72f0(%edx),%ebx ;...0fbe9a10 8da5af 4 0x03f83433: test %ebx,%ebx ;...85db 5 0x03f83435: jne 0x03f83460 ;...7529 6 0x03f83437: movl $0x1,-0x505a72f0(%ebp) ;...c785108d a5af01 7 0x03f83441: movb $0x0,-0x505a72f0(%edi) ;...c687108d a5af00 8 0x03f83448: mfence ;...0faef0 9 0x03f8344b: add $0x8,%esp ;...83c408 10 0x03f8344e: pop %ebp ;...5d 11 0x03f8344f: test %eax,0xb78ec000 ;...850500c0 8eb7 12 0x03f83455: ret ;...c3 13 0x03f83456: nopw 0x0(%eax,%eax,1) ;...66660f1f 840000 14 0x03f83460: mov -0x505a72f0(%ebp),%ebx ;...8b9d108d a5af 15 0x03f83466: test %edi,0xb78ec000 ;...853d00c0 8eb7 1 0x017b474c: push %ebp ;...55 2 0x017b474d: sub $0x8,%esp ;...81ec0800 0000 3 0x017b4753: mov $0x14c,%edi ;...bf4c0100 00 4 0x017b4758: movb $0x1,-0x507572f0(%edi) ;...c687108d 8aaf01 5 0x017b475f: mov $0x148,%ebp ;...bd480100 00 6 0x017b4764: mov $0x14d,%edx ;...ba4d0100 00 7 0x017b4769: movsbl -0x507572f0(%edx),%ebx ;...0fbe9a10 8d8aaf 8 0x017b4770: test %ebx,%ebx ;...85db 9 0x017b4772: jne 0x017b4790 ;...751c 10 0x017b4774: movl $0x1,-0x507572f0(%ebp) ;...c785108d 8aaf0111 0x017b477e: movb $0x0,-0x507572f0(%edi) ;...c687108d 8aaf00 12 0x017b4785: add $0x8,%esp ;...83c408 13 0x017b4788: pop %ebp ;...5d 1 0x036880f7: push %ebp ;...55 2 0x036880f8: mov %esp,%ebp ;...8bec 3 0x036880fa: sub $0x38,%esp ;...83ec38 4 0x036880fd: jmp 0x0368810a ;...e9080000 00 5 0x03688102: xchg %ax,%ax ;...6690 6 0x03688104: test %eax,0xb78b8100 ;...85050081 8bb7 7 0x0368810a: mov 0x8(%ecx),%eax ;...8b4108 8 0x0368810d: mov %eax,%esi ;...8bf0 9 0x0368810f: inc %esi ;...46 10 0x03688110: mov $0x9a3f03d0,%edi ;...bfd0033f 9a 11 0x03688115: mov 0x160(%edi),%edi ;...8bbf6001 0000 12 0x0368811b: mov %ecx,%edi ;...8bf9 13 0x0368811d: add $0x8,%edi ;...83c708 14 0x03688120: cmpxchg %esi,(%edi) ;...0fb137 15 0x03688123: mov $0x1,%eax ;...b8010000 00 16 0x03688128: je 0x03688133 ;...0f840500 0000 17 0x0368812e: mov $0x0,%eax ;...b8000000 00 18 0x03688133: cmp $0x0,%eax ;...83f800 19 0x03688136: je 0x03688104 ;...74cc 20 0x03688138: mov %esi,%eax ;...8bc6 21 0x0368813a: mov %ebp,%esp ;...8be5 22 0x0368813c: pop %ebp ;...5d 注意第14行的cmpxchg指令。之前我们看到编译器通过lock前缀把该指令提供给处理器。由于缺少SMP,JVM决定避免这种成本——与静态编译有些不同。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 2747 次