Synchronized的正确用法
-
修饰实例方法
/** * @Author: zenghzong * @Description: * @Date: Create in 16:18 2020/5/18 */ public class Main { public synchronized void test(){ } }
-
修饰静态方法
public class Main { public void test(){ synchronized(Main.class){ } } }
-
修饰代码块
public class Main { public void test1(){ synchronized(new test2()){ } } }
synchronized底层实现
java源代码
/** * @Author: zenghzong * @Description: * @Date: Create in 16:18 2020/5/18 */ public class Main { public synchronized void test(){ synchronized(new String()){ } } }
编译之后字节码,这里的对象头,他会关联到一个monitor对象。
Classfile /D:/myproject/Main.class Last modified 2020-5-18; size 490 bytes MD5 checksum 049256e45d8bd6241ed186ac84a10f8e Compiled from "Main.java" public class io.renren.modules.sys.Main minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#20 // java/lang/Object."<init>":()V #2 = Class #21 // java/lang/String #3 = Methodref #2.#20 // java/lang/String."<init>":()V #4 = Class #22 // io/renren/modules/sys/Main #5 = Class #23 // java/lang/Object #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 LocalVariableTable #11 = Utf8 this #12 = Utf8 Lio/renren/modules/sys/Main; #13 = Utf8 test #14 = Utf8 StackMapTable #15 = Class #22 // io/renren/modules/sys/Main #16 = Class #23 // java/lang/Object #17 = Class #24 // java/lang/Throwable #18 = Utf8 SourceFile #19 = Utf8 Main.java #20 = NameAndType #6:#7 // "<init>":()V #21 = Utf8 java/lang/String #22 = Utf8 io/renren/modules/sys/Main #23 = Utf8 java/lang/Object #24 = Utf8 java/lang/Throwable { public io.renren.modules.sys.Main(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lio/renren/modules/sys/Main; public synchronized void test(); descriptor: ()V flags: ACC_PUBLIC, ACC_SYNCHRONIZED Code: stack=2, locals=3, args_size=1 0: new #2 // class java/lang/String 3: dup 4: invokespecial #3 // Method java/lang/String."<init>":()V 7: dup 8: astore_1 9: monitorenter 10: aload_1 11: monitorexit 12: goto 20 15: astore_2 16: aload_1 17: monitorexit 18: aload_2 19: athrow 20: return Exception table: from to target type 10 12 15 any 15 18 15 any LineNumberTable: line 10: 0 line 12: 10 line 13: 20 LocalVariableTable: Start Length Slot Name Signature 0 21 0 this Lio/renren/modules/sys/Main; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 15 locals = [ class io/renren/modules/sys/Main, class java/lang/Object ] stack = [ class java/lang/Throwable ] frame_type = 250 /* chop */ offset_delta = 4 } SourceFile: "Main.java"
进入一个方法的时候,执行monitorenter,获得对象的所以权,如果monitor进入数为1,当前的这个线程就是这个monitor的owner,如果这时候已经是这个monitor的owner了,再次进入,就会更新技术成num+1。如果执行完monitorexit,num就-1,直到为0,然后才可以被其他线程持有。加锁的互斥,就是看你能否获得monitor的使用权,一旦你成为owner就是获得者。
monitor
monitor源码是C++写的,在虚拟机的ObjectMonitor.hpp文件中。该文件在线地址,该对象的结构如下
_recursions = 0; // 线程重入次数
_object = NULL; // 存储Monitor对象
_owner = NULL; // 持有当前线程的owner
_WaitSet = NULL; // wait状态的线程列表
_cxq = NULL ; // 单向列表
_EntryList = NULL ; // 处于等待锁状态block状态的线程列表
synchronized底层的源码就是引入了ObjectMonitor