公共代码

  1. public static void sleep() {
  2. try {
  3. Thread.sleep(100000000L);
  4. } catch (InterruptedException interruptedException) {
  5. interruptedException.printStackTrace();
  6. }
  7. }

锁实例方法

  1. public synchronized void method1() {
  2. sleep();
  3. }
  4. public void method0() {
  5. synchronized (this) {
  6. sleep();
  7. }
  8. }

字节码

  1. // access flags 0x21 method1()
  2. public synchronized method1()V
  3. L0
  4. LINENUMBER 34 L0
  5. INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
  6. L1
  7. LINENUMBER 35 L1
  8. RETURN
  9. L2
  10. LOCALVARIABLE this Lcom/raycloud/api/common/core/http/ThreadTest; L0 L2 0
  11. MAXSTACK = 0
  12. MAXLOCALS = 1
  13. ===================================================================================
  14. public method0()V
  15. TRYCATCHBLOCK L0 L1 L2 null
  16. TRYCATCHBLOCK L2 L3 L2 null
  17. L4
  18. LINENUMBER 47 L4
  19. ALOAD 0
  20. DUP
  21. ASTORE 1
  22. MONITORENTER
  23. L0
  24. LINENUMBER 48 L0
  25. INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
  26. L5
  27. LINENUMBER 49 L5
  28. ALOAD 1
  29. MONITOREXIT
  30. L1
  31. GOTO L6
  32. L2
  33. FRAME FULL [com/raycloud/api/common/core/http/ThreadTest java/lang/Object] [java/lang/Throwable]
  34. ASTORE 2
  35. ALOAD 1
  36. MONITOREXIT
  37. L3
  38. ALOAD 2
  39. ATHROW
  40. L6
  41. LINENUMBER 50 L6
  42. FRAME CHOP 1
  43. RETURN
  44. L7
  45. LOCALVARIABLE this Lcom/raycloud/api/common/core/http/ThreadTest; L4 L7 0
  46. MAXSTACK = 2
  47. MAXLOCALS = 3

其中的区别在于 synchronized 放方法上就是一个简单的方法访问标志,而放方法内部,同步this的处理就有 MONITORENTERMONITOREXIT 等数据了。

Q: 锁实例方法和锁this代码块,是不是同一个monitor lock呢?
查看堆栈

  1. public class ThreadTest {
  2. public static void main(String[] args) throws Exception {
  3. ThreadTest threadTest = new ThreadTest();
  4. new Thread(threadTest::method1).start();
  5. Thread.sleep(100L
  6. );
  7. threadTest.method0();
  8. }
  9. }
  1. "main" #1 prio=5 os_prio=31 tid=0x00007fe61780e800 nid=0xd03 waiting for monitor entry [0x000070000644d000]
  2. java.lang.Thread.State: BLOCKED (on object monitor)
  3. at com.raycloud.api.common.core.http.ThreadTest.method0(ThreadTest.java:32)
  4. - waiting to lock <0x000000076ae40ef8> (a com.raycloud.api.common.core.http.ThreadTest)
  5. at com.raycloud.api.common.core.http.ThreadTest.main(ThreadTest.java:14)
  6. "Thread-0" #11 prio=5 os_prio=31 tid=0x00007fe6198f7000 nid=0x5a03 waiting on condition [0x0000700007a12000]
  7. java.lang.Thread.State: TIMED_WAITING (sleeping)
  8. at java.lang.Thread.sleep(Native Method)
  9. at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:24)
  10. at com.raycloud.api.common.core.http.ThreadTest.method1(ThreadTest.java:18)
  11. - locked <0x000000076ae40ef8> (a com.raycloud.api.common.core.http.ThreadTest)
  12. at com.raycloud.api.common.core.http.ThreadTest$$Lambda$1/1940447180.run(Unknown Source)
  13. at java.lang.Thread.run(Thread.java:748)

locked <0x000000076ae40ef8> waiting to lock <0x000000076ae40ef8>

⚠️ 注意

锁实例,针对的是每一个实例对象,所以每一个实例对象都持有一个lock,因此不能实例之间的 synchronized 是相互不影响的。

  1. public class ThreadTest {
  2. public static void main(String[] args) throws Exception {
  3. ThreadTest first = new ThreadTest();
  4. ThreadTest second = new ThreadTest();
  5. new Thread(first::method1).start();
  6. new Thread(second::method1).start();
  7. }
  8. }
  1. "Thread-1" #12 prio=5 os_prio=31 tid=0x00007f9ade156000 nid=0x5a03 waiting on condition [0x0000700001b1a000]
  2. java.lang.Thread.State: TIMED_WAITING (sleeping)
  3. at java.lang.Thread.sleep(Native Method)
  4. at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:25)
  5. at com.raycloud.api.common.core.http.ThreadTest.method1(ThreadTest.java:19)
  6. - locked <0x000000076ae40f30> (a com.raycloud.api.common.core.http.ThreadTest)
  7. at com.raycloud.api.common.core.http.ThreadTest$$Lambda$2/2121744517.run(Unknown Source)
  8. at java.lang.Thread.run(Thread.java:748)
  9. "Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9adf89c000 nid=0xa803 waiting on condition [0x0000700001a17000]
  10. java.lang.Thread.State: TIMED_WAITING (sleeping)
  11. at java.lang.Thread.sleep(Native Method)
  12. at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:25)
  13. at com.raycloud.api.common.core.http.ThreadTest.method1(ThreadTest.java:19)
  14. - locked <0x000000076ae40f20> (a com.raycloud.api.common.core.http.ThreadTest)
  15. at com.raycloud.api.common.core.http.ThreadTest$$Lambda$1/1940447180.run(Unknown Source)
  16. at java.lang.Thread.run(Thread.java:748)

锁静态方法

  1. public synchronized static void method2() {
  2. sleep();
  3. }
  4. public static void method3() {
  5. synchronized (ThreadTest.class) {
  6. sleep();
  7. }
  8. }

字节码

  1. // access flags 0x29
  2. public static synchronized method2()V
  3. L0
  4. LINENUMBER 37 L0
  5. INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
  6. L1
  7. LINENUMBER 38 L1
  8. RETURN
  9. MAXSTACK = 0
  10. MAXLOCALS = 0
  11. ===================================================================================
  12. // access flags 0x9
  13. public static method3()V
  14. TRYCATCHBLOCK L0 L1 L2 null
  15. TRYCATCHBLOCK L2 L3 L2 null
  16. L4
  17. LINENUMBER 41 L4
  18. LDC Lcom/raycloud/api/common/core/http/ThreadTest;.class
  19. DUP
  20. ASTORE 0
  21. MONITORENTER
  22. L0
  23. LINENUMBER 42 L0
  24. INVOKESTATIC com/raycloud/api/common/core/http/ThreadTest.sleep ()V
  25. L5
  26. LINENUMBER 43 L5
  27. ALOAD 0
  28. MONITOREXIT
  29. L1
  30. GOTO L6
  31. L2
  32. FRAME FULL [java/lang/Object] [java/lang/Throwable]
  33. ASTORE 1
  34. ALOAD 0
  35. MONITOREXIT
  36. L3
  37. ALOAD 1
  38. ATHROW
  39. L6
  40. LINENUMBER 44 L6
  41. FRAME CHOP 1
  42. RETURN
  43. MAXSTACK = 2
  44. MAXLOCALS = 2

和锁实例方法一样的配置,不过这次aload,和store的是 ThreadTest.class, 所谓锁的对象发生了变化.
静态方法和 xxx.class是不是同一把锁呢

  1. public class ThreadTest {
  2. public static void main(String[] args) throws Exception {
  3. new Thread(ThreadTest::method2).start();
  4. Thread.sleep(100L
  5. );
  6. ThreadTest.method3();
  7. }
  8. }
  1. "main" #1 prio=5 os_prio=31 tid=0x00007fd11881a000 nid=0xd03 waiting for monitor entry [0x00007000054b8000]
  2. java.lang.Thread.State: BLOCKED (on object monitor)
  3. at com.raycloud.api.common.core.http.ThreadTest.method3(ThreadTest.java:41)
  4. - waiting to lock <0x000000076ae3e398> (a java.lang.Class for com.raycloud.api.common.core.http.ThreadTest)
  5. at com.raycloud.api.common.core.http.ThreadTest.main(ThreadTest.java:13)
  6. "Thread-0" #11 prio=5 os_prio=31 tid=0x00007fd11694e000 nid=0xa703 waiting on condition [0x00007000069fa000]
  7. java.lang.Thread.State: TIMED_WAITING (sleeping)
  8. at java.lang.Thread.sleep(Native Method)
  9. at com.raycloud.api.common.core.http.ThreadTest.sleep(ThreadTest.java:23)
  10. at com.raycloud.api.common.core.http.ThreadTest.method2(ThreadTest.java:36)
  11. - locked <0x000000076ae3e398> (a java.lang.Class for com.raycloud.api.common.core.http.ThreadTest)
  12. at com.raycloud.api.common.core.http.ThreadTest$$Lambda$1/1940447180.run(Unknown Source)
  13. 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)

可重入性

当同步锁住一个实例方法进行调用时,是否可以多次调用同一个方法。

答案是可以,反证法如下:

  • 如果不能多次同步调用,就会出现死锁了,我要向下执行就需要再一次拥有锁,但是又不能获得锁
  • 所以,可重入性是必然的