公共代码
public static void sleep() {try {Thread.sleep(100000000L);} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}}
锁实例方法
public synchronized void method1() {sleep();}public void method0() {synchronized (this) {sleep();}}
字节码
// access flags 0x21 method1()public synchronized method1()VL0LINENUMBER 34 L0INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()VL1LINENUMBER 35 L1RETURNL2LOCALVARIABLE this Lcom/raycloud/api/common/core/http/ThreadTest; L0 L2 0MAXSTACK = 0MAXLOCALS = 1===================================================================================public method0()VTRYCATCHBLOCK L0 L1 L2 nullTRYCATCHBLOCK L2 L3 L2 nullL4LINENUMBER 47 L4ALOAD 0DUPASTORE 1MONITORENTERL0LINENUMBER 48 L0INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()VL5LINENUMBER 49 L5ALOAD 1MONITOREXITL1GOTO L6L2FRAME FULL [com/raycloud/api/common/core/http/ThreadTest java/lang/Object] [java/lang/Throwable]ASTORE 2ALOAD 1MONITOREXITL3ALOAD 2ATHROWL6LINENUMBER 50 L6FRAME CHOP 1RETURNL7LOCALVARIABLE this Lcom/raycloud/api/common/core/http/ThreadTest; L4 L7 0MAXSTACK = 2MAXLOCALS = 3
其中的区别在于 synchronized 放方法上就是一个简单的方法访问标志,而放方法内部,同步this的处理就有 MONITORENTER 和 MONITOREXIT 等数据了。
Q: 锁实例方法和锁this代码块,是不是同一个monitor lock呢?
查看堆栈
public class ThreadTest {public static void main(String[] args) throws Exception {ThreadTest threadTest = new ThreadTest();new Thread(threadTest::method1).start();Thread.sleep(100L);threadTest.method0();}}
"main" #1 prio=5 os_prio=31 tid=0x00007fe61780e800 nid=0xd03 waiting for monitor entry [0x000070000644d000]java.lang.Thread.State: BLOCKED (on object monitor)at com.raycloud.api.common.core.http.ThreadTest.method0(ThreadTest.java:32)- waiting to lock <0x000000076ae40ef8> (a com.raycloud.api.common.core.http.ThreadTest)at com.raycloud.api.common.core.http.ThreadTest.main(ThreadTest.java:14)"Thread-0" #11 prio=5 os_prio=31 tid=0x00007fe6198f7000 nid=0x5a03 waiting on condition [0x0000700007a12000]java.lang.Thread.State: TIMED_WAITING (sleeping)at java.lang.Thread.sleep(Native Method)at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:24)at com.raycloud.api.common.core.http.ThreadTest.method1(ThreadTest.java:18)- locked <0x000000076ae40ef8> (a com.raycloud.api.common.core.http.ThreadTest)at com.raycloud.api.common.core.http.ThreadTest$$Lambda$1/1940447180.run(Unknown Source)at java.lang.Thread.run(Thread.java:748)
locked <0x000000076ae40ef8> waiting to lock <0x000000076ae40ef8>
⚠️ 注意
锁实例,针对的是每一个实例对象,所以每一个实例对象都持有一个lock,因此不能实例之间的 synchronized 是相互不影响的。
public class ThreadTest {public static void main(String[] args) throws Exception {ThreadTest first = new ThreadTest();ThreadTest second = new ThreadTest();new Thread(first::method1).start();new Thread(second::method1).start();}}
"Thread-1" #12 prio=5 os_prio=31 tid=0x00007f9ade156000 nid=0x5a03 waiting on condition [0x0000700001b1a000]java.lang.Thread.State: TIMED_WAITING (sleeping)at java.lang.Thread.sleep(Native Method)at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:25)at com.raycloud.api.common.core.http.ThreadTest.method1(ThreadTest.java:19)- locked <0x000000076ae40f30> (a com.raycloud.api.common.core.http.ThreadTest)at com.raycloud.api.common.core.http.ThreadTest$$Lambda$2/2121744517.run(Unknown Source)at java.lang.Thread.run(Thread.java:748)"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9adf89c000 nid=0xa803 waiting on condition [0x0000700001a17000]java.lang.Thread.State: TIMED_WAITING (sleeping)at java.lang.Thread.sleep(Native Method)at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:25)at com.raycloud.api.common.core.http.ThreadTest.method1(ThreadTest.java:19)- locked <0x000000076ae40f20> (a com.raycloud.api.common.core.http.ThreadTest)at com.raycloud.api.common.core.http.ThreadTest$$Lambda$1/1940447180.run(Unknown Source)at java.lang.Thread.run(Thread.java:748)
锁静态方法
public synchronized static void method2() {sleep();}public static void method3() {synchronized (ThreadTest.class) {sleep();}}
字节码
// access flags 0x29public static synchronized method2()VL0LINENUMBER 37 L0INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()VL1LINENUMBER 38 L1RETURNMAXSTACK = 0MAXLOCALS = 0===================================================================================// access flags 0x9public static method3()VTRYCATCHBLOCK L0 L1 L2 nullTRYCATCHBLOCK L2 L3 L2 nullL4LINENUMBER 41 L4LDC Lcom/raycloud/api/common/core/http/ThreadTest;.classDUPASTORE 0MONITORENTERL0LINENUMBER 42 L0INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()VL5LINENUMBER 43 L5ALOAD 0MONITOREXITL1GOTO L6L2FRAME FULL [java/lang/Object] [java/lang/Throwable]ASTORE 1ALOAD 0MONITOREXITL3ALOAD 1ATHROWL6LINENUMBER 44 L6FRAME CHOP 1RETURNMAXSTACK = 2MAXLOCALS = 2
和锁实例方法一样的配置,不过这次aload,和store的是 ThreadTest.class, 所谓锁的对象发生了变化.
静态方法和 xxx.class是不是同一把锁呢
public class ThreadTest {public static void main(String[] args) throws Exception {new Thread(ThreadTest::method2).start();Thread.sleep(100L);ThreadTest.method3();}}
"main" #1 prio=5 os_prio=31 tid=0x00007fd11881a000 nid=0xd03 waiting for monitor entry [0x00007000054b8000]java.lang.Thread.State: BLOCKED (on object monitor)at com.raycloud.api.common.core.http.ThreadTest.method3(ThreadTest.java:41)- waiting to lock <0x000000076ae3e398> (a java.lang.Class for com.raycloud.api.common.core.http.ThreadTest)at com.raycloud.api.common.core.http.ThreadTest.main(ThreadTest.java:13)"Thread-0" #11 prio=5 os_prio=31 tid=0x00007fd11694e000 nid=0xa703 waiting on condition [0x00007000069fa000]java.lang.Thread.State: TIMED_WAITING (sleeping)at java.lang.Thread.sleep(Native Method)at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:23)at com.raycloud.api.common.core.http.ThreadTest.method2(ThreadTest.java:36)- locked <0x000000076ae3e398> (a java.lang.Class for com.raycloud.api.common.core.http.ThreadTest)at com.raycloud.api.common.core.http.ThreadTest$$Lambda$1/1940447180.run(Unknown Source)at java.lang.Thread.run(Thread.java:748)
locked <0x000000076ae3e398> (a java.lang.Class for com.raycloud.api.common.core.http.ThreadTest)
waiting to lock <0x000000076ae3e398> (a java.lang.Class for com.raycloud.api.common.core.http.ThreadTest)
可重入性
当同步锁住一个实例方法进行调用时,是否可以多次调用同一个方法。
答案是可以,反证法如下:
- 如果不能多次同步调用,就会出现死锁了,我要向下执行就需要再一次拥有锁,但是又不能获得锁
- 所以,可重入性是必然的
