公共代码
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()V
L0
LINENUMBER 34 L0
INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
L1
LINENUMBER 35 L1
RETURN
L2
LOCALVARIABLE this Lcom/raycloud/api/common/core/http/ThreadTest; L0 L2 0
MAXSTACK = 0
MAXLOCALS = 1
===================================================================================
public method0()V
TRYCATCHBLOCK L0 L1 L2 null
TRYCATCHBLOCK L2 L3 L2 null
L4
LINENUMBER 47 L4
ALOAD 0
DUP
ASTORE 1
MONITORENTER
L0
LINENUMBER 48 L0
INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
L5
LINENUMBER 49 L5
ALOAD 1
MONITOREXIT
L1
GOTO L6
L2
FRAME FULL [com/raycloud/api/common/core/http/ThreadTest java/lang/Object] [java/lang/Throwable]
ASTORE 2
ALOAD 1
MONITOREXIT
L3
ALOAD 2
ATHROW
L6
LINENUMBER 50 L6
FRAME CHOP 1
RETURN
L7
LOCALVARIABLE this Lcom/raycloud/api/common/core/http/ThreadTest; L4 L7 0
MAXSTACK = 2
MAXLOCALS = 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 0x29
public static synchronized method2()V
L0
LINENUMBER 37 L0
INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
L1
LINENUMBER 38 L1
RETURN
MAXSTACK = 0
MAXLOCALS = 0
===================================================================================
// access flags 0x9
public static method3()V
TRYCATCHBLOCK L0 L1 L2 null
TRYCATCHBLOCK L2 L3 L2 null
L4
LINENUMBER 41 L4
LDC Lcom/raycloud/api/common/core/http/ThreadTest;.class
DUP
ASTORE 0
MONITORENTER
L0
LINENUMBER 42 L0
INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
L5
LINENUMBER 43 L5
ALOAD 0
MONITOREXIT
L1
GOTO L6
L2
FRAME FULL [java/lang/Object] [java/lang/Throwable]
ASTORE 1
ALOAD 0
MONITOREXIT
L3
ALOAD 1
ATHROW
L6
LINENUMBER 44 L6
FRAME CHOP 1
RETURN
MAXSTACK = 2
MAXLOCALS = 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)
可重入性
当同步锁住一个实例方法进行调用时,是否可以多次调用同一个方法。
答案是可以,反证法如下:
- 如果不能多次同步调用,就会出现死锁了,我要向下执行就需要再一次拥有锁,但是又不能获得锁
- 所以,可重入性是必然的