今天我们来分析一下java中synchronized关键字。首先来看一段java代码:(本地编译环境为mac,jdk1.8的环境)
Demo.java
1 package com.example.springcloud.provider.demo;2 3 public class Demo {4 private boolean isOk = true;5 6 public void test(){7 isOk=false;8 }9 }
编译周后的Demo.class二进制文件:
Demo.class
1 cafe babe 0000 0034 0015 0a00 0400 1109 2 0003 0012 0700 1307 0014 0100 0469 734f 3 6b01 0001 5a01 0006 3c69 6e69 743e 0100 4 0328 2956 0100 0443 6f64 6501 000f 4c69 5 6e65 4e75 6d62 6572 5461 626c 6501 0012 6 4c6f 6361 6c56 6172 6961 626c 6554 6162 7 6c65 0100 0474 6869 7301 002c 4c63 6f6d 8 2f65 7861 6d70 6c65 2f73 7072 696e 6763 9 6c6f 7564 2f70 726f 7669 6465 722f 646510 6d6f 2f44 656d 6f3b 0100 0474 6573 740111 000a 536f 7572 6365 4669 6c65 0100 094412 656d 6f2e 6a61 7661 0c00 0700 080c 000513 0006 0100 2a63 6f6d 2f65 7861 6d70 6c6514 2f73 7072 696e 6763 6c6f 7564 2f70 726f15 7669 6465 722f 6465 6d6f 2f44 656d 6f0116 0010 6a61 7661 2f6c 616e 672f 4f62 6a6517 6374 0021 0003 0004 0000 0001 0002 000518 0006 0000 0002 0001 0007 0008 0001 000919 0000 0038 0002 0001 0000 000a 2ab7 000120 2a04 b500 02b1 0000 0002 000a 0000 000a21 0002 0000 0003 0004 0004 000b 0000 000c22 0001 0000 000a 000c 000d 0000 0001 000e23 0008 0001 0009 0000 0034 0002 0001 000024 0006 2a03 b500 02b1 0000 0002 000a 000025 000a 0002 0000 0007 0005 0008 000b 000026 000c 0001 0000 0006 000c 000d 0000 000127 000f 0000 0002 0010
使用javap -v Demo.class > Demo.txt 文件得到反编译的汇编语言:
Demo.txt
1 Classfile /Users/shiwen/IdeaProjects/springcloud/example-springcloud-provider/target/classes/com/example/springcloud/provider/demo/Demo.class 2 Last modified 2017-10-11; size 424 bytes 3 MD5 checksum 1f57b26a93d1cc466ff58bcec5ff37fb 4 Compiled from "Demo.java" 5 public class com.example.springcloud.provider.demo.Demo 6 minor version: 0 7 major version: 52 8 flags: ACC_PUBLIC, ACC_SUPER 9 Constant pool:10 #1 = Methodref #4.#17 // java/lang/Object."":()V11 #2 = Fieldref #3.#18 // com/example/springcloud/provider/demo/Demo.isOk:Z12 #3 = Class #19 // com/example/springcloud/provider/demo/Demo13 #4 = Class #20 // java/lang/Object14 #5 = Utf8 isOk15 #6 = Utf8 Z16 #7 = Utf8 17 #8 = Utf8 ()V18 #9 = Utf8 Code19 #10 = Utf8 LineNumberTable20 #11 = Utf8 LocalVariableTable21 #12 = Utf8 this22 #13 = Utf8 Lcom/example/springcloud/provider/demo/Demo;23 #14 = Utf8 test24 #15 = Utf8 SourceFile25 #16 = Utf8 Demo.java26 #17 = NameAndType #7:#8 // " ":()V27 #18 = NameAndType #5:#6 // isOk:Z28 #19 = Utf8 com/example/springcloud/provider/demo/Demo29 #20 = Utf8 java/lang/Object30 {31 public com.example.springcloud.provider.demo.Demo();32 descriptor: ()V33 flags: ACC_PUBLIC34 Code:35 stack=2, locals=1, args_size=136 0: aload_037 1: invokespecial #1 // Method java/lang/Object." ":()V38 4: aload_039 5: iconst_140 6: putfield #2 // Field isOk:Z41 9: return42 LineNumberTable:43 line 3: 044 line 4: 445 LocalVariableTable:46 Start Length Slot Name Signature47 0 10 0 this Lcom/example/springcloud/provider/demo/Demo;48 49 public void test();50 descriptor: ()V51 flags: ACC_PUBLIC52 Code:53 stack=2, locals=1, args_size=154 0: aload_055 1: iconst_056 2: putfield #2 // Field isOk:Z57 5: return58 LineNumberTable:59 line 7: 060 line 8: 561 LocalVariableTable:62 Start Length Slot Name Signature63 0 6 0 this Lcom/example/springcloud/provider/demo/Demo;64 }65 SourceFile: "Demo.java"
修改Demo.java文件在方法中新增synchronized如下:
package com.example.springcloud.provider.demo;public class Demo { private boolean isOk = true; private synchronized void test(){
isOk=false;
} }
反编译为汇编后:(不同的地方用黄色标识出来了)
1 Classfile /Users/shiwen/IdeaProjects/springcloud/example-springcloud-provider/target/classes/com/example/springcloud/provider/demo/Demo.class 2 Last modified 2017-10-11; size 424 bytes 3 MD5 checksum 000d5f4eb139b3d12c483f7087c0c970 4 Compiled from "Demo.java" 5 public class com.example.springcloud.provider.demo.Demo 6 minor version: 0 7 major version: 52 8 flags: ACC_PUBLIC, ACC_SUPER 9 Constant pool:10 #1 = Methodref #4.#17 // java/lang/Object."":()V11 #2 = Fieldref #3.#18 // com/example/springcloud/provider/demo/Demo.isOk:Z12 #3 = Class #19 // com/example/springcloud/provider/demo/Demo13 #4 = Class #20 // java/lang/Object14 #5 = Utf8 isOk15 #6 = Utf8 Z16 #7 = Utf8 17 #8 = Utf8 ()V18 #9 = Utf8 Code19 #10 = Utf8 LineNumberTable20 #11 = Utf8 LocalVariableTable21 #12 = Utf8 this22 #13 = Utf8 Lcom/example/springcloud/provider/demo/Demo;23 #14 = Utf8 test24 #15 = Utf8 SourceFile25 #16 = Utf8 Demo.java26 #17 = NameAndType #7:#8 // " ":()V27 #18 = NameAndType #5:#6 // isOk:Z28 #19 = Utf8 com/example/springcloud/provider/demo/Demo29 #20 = Utf8 java/lang/Object30 {31 public com.example.springcloud.provider.demo.Demo();32 descriptor: ()V33 flags: ACC_PUBLIC34 Code:35 stack=2, locals=1, args_size=136 0: aload_037 1: invokespecial #1 // Method java/lang/Object." ":()V38 4: aload_039 5: iconst_140 6: putfield #2 // Field isOk:Z41 9: return42 LineNumberTable:43 line 3: 044 line 4: 445 LocalVariableTable:46 Start Length Slot Name Signature47 0 10 0 this Lcom/example/springcloud/provider/demo/Demo;48 49 public synchronized void test();50 descriptor: ()V51 flags: ACC_PUBLIC, ACC_SYNCHRONIZED52 Code:53 stack=2, locals=1, args_size=154 0: aload_055 1: iconst_056 2: putfield #2 // Field isOk:Z57 5: return58 LineNumberTable:59 line 7: 060 line 8: 561 LocalVariableTable:62 Start Length Slot Name Signature63 0 6 0 this Lcom/example/springcloud/provider/demo/Demo;64 }65 SourceFile: "Demo.java"
改为synchronized代码块:
1 package com.example.springcloud.provider.demo; 2 3 public class Demo { 4 private boolean isOk = true; 5 6 public void test() { 7 synchronized (this) { 8 isOk = false; 9 }10 }11 }
反编译汇编为:
1 Classfile /Users/shiwen/IdeaProjects/springcloud/example-springcloud-provider/target/classes/com/example/springcloud/provider/demo/Demo.class 2 Last modified 2017-10-11; size 536 bytes 3 MD5 checksum 64305bd51f24f439444d9240efd483fd 4 Compiled from "Demo.java" 5 public class com.example.springcloud.provider.demo.Demo 6 minor version: 0 7 major version: 52 8 flags: ACC_PUBLIC, ACC_SUPER 9 Constant pool:10 #1 = Methodref #4.#21 // java/lang/Object."":()V11 #2 = Fieldref #3.#22 // com/example/springcloud/provider/demo/Demo.isOk:Z12 #3 = Class #23 // com/example/springcloud/provider/demo/Demo13 #4 = Class #24 // java/lang/Object14 #5 = Utf8 isOk15 #6 = Utf8 Z16 #7 = Utf8 17 #8 = Utf8 ()V18 #9 = Utf8 Code19 #10 = Utf8 LineNumberTable20 #11 = Utf8 LocalVariableTable21 #12 = Utf8 this22 #13 = Utf8 Lcom/example/springcloud/provider/demo/Demo;23 #14 = Utf8 test24 #15 = Utf8 StackMapTable25 #16 = Class #23 // com/example/springcloud/provider/demo/Demo26 #17 = Class #24 // java/lang/Object27 #18 = Class #25 // java/lang/Throwable28 #19 = Utf8 SourceFile29 #20 = Utf8 Demo.java30 #21 = NameAndType #7:#8 // " ":()V31 #22 = NameAndType #5:#6 // isOk:Z32 #23 = Utf8 com/example/springcloud/provider/demo/Demo33 #24 = Utf8 java/lang/Object34 #25 = Utf8 java/lang/Throwable35 {36 public com.example.springcloud.provider.demo.Demo();37 descriptor: ()V38 flags: ACC_PUBLIC39 Code:40 stack=2, locals=1, args_size=141 0: aload_042 1: invokespecial #1 // Method java/lang/Object." ":()V43 4: aload_044 5: iconst_145 6: putfield #2 // Field isOk:Z46 9: return47 LineNumberTable:48 line 3: 049 line 4: 450 LocalVariableTable:51 Start Length Slot Name Signature52 0 10 0 this Lcom/example/springcloud/provider/demo/Demo;53 54 public void test();55 descriptor: ()V56 flags: ACC_PUBLIC57 Code:58 stack=2, locals=3, args_size=159 0: aload_060 1: dup61 2: astore_162 3: monitorenter63 4: aload_064 5: iconst_065 6: putfield #2 // Field isOk:Z66 9: aload_167 10: monitorexit68 11: goto 1969 14: astore_270 15: aload_171 16: monitorexit72 17: aload_273 18: athrow74 19: return75 Exception table:76 from to target type77 4 11 14 any78 14 17 14 any79 LineNumberTable:80 line 7: 081 line 8: 482 line 9: 983 line 10: 1984 LocalVariableTable:85 Start Length Slot Name Signature86 0 20 0 this Lcom/example/springcloud/provider/demo/Demo;87 StackMapTable: number_of_entries = 288 frame_type = 255 /* full_frame */89 offset_delta = 1490 locals = [ class com/example/springcloud/provider/demo/Demo, class java/lang/Object ]91 stack = [ class java/lang/Throwable ]92 frame_type = 250 /* chop */93 offset_delta = 494 }95 SourceFile: "Demo.java"
和synchronized方法对比如下:
给isOk增加volatile关键字后
1 Classfile /Users/shiwen/IdeaProjects/springcloud/example-springcloud-provider/target/classes/com/example/springcloud/provider/demo/Demo.class 2 Last modified 2017-10-11; size 536 bytes 3 MD5 checksum 8dc910b015c7d5af2feac29d19f519a1 4 Compiled from "Demo.java" 5 public class com.example.springcloud.provider.demo.Demo 6 minor version: 0 7 major version: 52 8 flags: ACC_PUBLIC, ACC_SUPER 9 Constant pool:10 #1 = Methodref #4.#21 // java/lang/Object."":()V11 #2 = Fieldref #3.#22 // com/example/springcloud/provider/demo/Demo.isOk:Z12 #3 = Class #23 // com/example/springcloud/provider/demo/Demo13 #4 = Class #24 // java/lang/Object14 #5 = Utf8 isOk15 #6 = Utf8 Z16 #7 = Utf8 17 #8 = Utf8 ()V18 #9 = Utf8 Code19 #10 = Utf8 LineNumberTable20 #11 = Utf8 LocalVariableTable21 #12 = Utf8 this22 #13 = Utf8 Lcom/example/springcloud/provider/demo/Demo;23 #14 = Utf8 test24 #15 = Utf8 StackMapTable25 #16 = Class #23 // com/example/springcloud/provider/demo/Demo26 #17 = Class #24 // java/lang/Object27 #18 = Class #25 // java/lang/Throwable28 #19 = Utf8 SourceFile29 #20 = Utf8 Demo.java30 #21 = NameAndType #7:#8 // " ":()V31 #22 = NameAndType #5:#6 // isOk:Z32 #23 = Utf8 com/example/springcloud/provider/demo/Demo33 #24 = Utf8 java/lang/Object34 #25 = Utf8 java/lang/Throwable35 {36 public volatile boolean isOk;37 descriptor: Z38 flags: ACC_PUBLIC, ACC_VOLATILE 39 40 public com.example.springcloud.provider.demo.Demo();41 descriptor: ()V42 flags: ACC_PUBLIC43 Code:44 stack=2, locals=1, args_size=145 0: aload_046 1: invokespecial #1 // Method java/lang/Object." ":()V47 4: aload_048 5: iconst_149 6: putfield #2 // Field isOk:Z50 9: return51 LineNumberTable:52 line 3: 053 line 4: 454 LocalVariableTable:55 Start Length Slot Name Signature56 0 10 0 this Lcom/example/springcloud/provider/demo/Demo;57 58 public void test();59 descriptor: ()V60 flags: ACC_PUBLIC61 Code:62 stack=2, locals=3, args_size=163 0: aload_064 1: dup65 2: astore_166 3: monitorenter67 4: aload_068 5: iconst_069 6: putfield #2 // Field isOk:Z70 9: aload_171 10: monitorexit72 11: goto 1973 14: astore_274 15: aload_175 16: monitorexit76 17: aload_277 18: athrow78 19: return79 Exception table:80 from to target type81 4 11 14 any82 14 17 14 any83 LineNumberTable:84 line 7: 085 line 8: 486 line 9: 987 line 10: 1988 LocalVariableTable:89 Start Length Slot Name Signature90 0 20 0 this Lcom/example/springcloud/provider/demo/Demo;91 StackMapTable: number_of_entries = 292 frame_type = 255 /* full_frame */93 offset_delta = 1494 locals = [ class com/example/springcloud/provider/demo/Demo, class java/lang/Object ]95 stack = [ class java/lang/Throwable ]96 frame_type = 250 /* chop */97 offset_delta = 498 }99 SourceFile: "Demo.java"