关于java:并发王者课青铜7顺藤摸瓜如何从synchronized中的锁认识Monitor

30次阅读

共计 4249 个字符,预计需要花费 11 分钟才能阅读完成。

在后面的文章中,咱们曾经体验过 synchronized 的用法,并对锁的概念和原理做了简略的介绍。然而,你可能曾经察觉到,有一个概念 仿佛总是和 synchronized这两个概念 如影相随 ,很多人也比拟喜爱问它们之间的区别,这个概念就是Monitor,也叫 监视器

所以,在解说完 synchronized、锁之后,文本将为你解说 Monitor,揭示它们之间那些公开的机密,心愿你不再蛊惑。

首先,你要明确的是,Monitor 作为一种同步机制,它并非 Java 所特有,但 Java 实现了这一机制。

为了具象地了解 Monitor 这一抽象概念,咱们先来剖析身边的一个常见场景。

一、从医院排队就诊机制了解 Monitor

置信你肯定有过来医院就诊的经验。咱们去医院时,状况个别是这样的:

  • 首先,咱们在 门诊大厅 前台或自助挂号机 进行挂号
  • 随后,挂号完结后咱们找到对应的 诊室就诊

    • 诊室每次只能有一个患者就诊;
    • 如果此时诊室闲暇,间接进入就诊;
    • 如果此时诊室内有患者正在就诊,那么咱们进入 候诊室,期待叫号;
  • 就诊完结后,走出就诊室 ,候诊室的 下一位候诊患者 进入就诊室。

这个就诊过程你肯定耳熟能详,了解起来必然毫不费力气。咱们做了一张图展现图下:

认真看这幅图中的就诊过程,如果你了解了这个过程,你就了解了 Monitor. 这么简略吗?不要狐疑本人,是的。你居然早已了解 Monitor 机制

不要小看这个机制,它可是生存中的智慧体现。在这个就诊机制中,它起到了 两个关键性的作用

  • 互斥(mutual exclusion):每次只容许一个患者进入候诊室就诊;
  • 合作(cooperation):就诊室中的患者就诊完结后,能够告诉候诊区的下一位患者。

明确了吗?你在医院就诊的过程居然和 Monitor 的机制简直截然不同。咱们换个形式来形容 Monitor 在计算机科学中的作用:

  • 互斥(mutual exclusion):每次只容许一个线程进入临界区;
  • 合作(cooperation):当临界区的线程执行完结后满足特定条件时,能够告诉其余的期待线程进入。

而就诊过程中的 门诊大厅 就诊室 候诊室 则恰好对应着 Monitor 中的三个要害概念。其中:

  • 门诊大厅 :所有待进入的线程都必须先在 入口(Entry Set)挂号才有资格;
  • 就诊室 :一个每次只能有一个线程进入的 非凡房间(Special Room)
  • 候诊室 :就诊室忙碌时,进入 期待区(Wait Set)

咱们把下面的图稍作调整,就能够看到 Monitor 在 Java 中的模样:

比照来看,置信你曾经很直观地了解 Monitor 机制。再一回味,你会发现 synchronized 正是对 Monitor 机制的一种实现。而在 Java 中, 每一个对象都会关联一个监视器

二、从 synchronized 源码感触 Monitor

既然 synchronized 是对 Monitor 机制的一种实现,为了让你更有体感,咱们能够写一段 极简代码 一探到底。

这段代码极为简略,然而够用,咱们在代码中应用了 synchronized 关键字:

public class SyncMonitorDemo {public static void main(String[] args) {Object o = new Object();
        synchronized (o) {System.out.println("locking...");
        }
    }
}

代码写好后,别离执行 javac SyncMonitorDemo.javajavap -v SyncMonitorDemo.class,随后你就能失去上面这样的字节码:

Classfile SyncMonitorDemo.class
  Last modified May 26, 2021; size 684 bytes
  MD5 checksum e366920f22845e98c45f26531596d6cf
  Compiled from "SyncMonitorDemo.java"
public class cn.tao.king.juc.execises1.SyncMonitorDemo
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #2.#22         // java/lang/Object."<init>":()V
   #2 = Class              #23            // java/lang/Object
   #3 = Fieldref           #24.#25        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = String             #26            // locking...
   #5 = Methodref          #27.#28        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #6 = Class              #29            // cn/tao/king/juc/execises1/SyncMonitorDemo
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcn/tao/king/juc/execises1/SyncMonitorDemo;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               o
  #19 = Utf8               Ljava/lang/Object;
  #20 = Utf8               SourceFile
  #21 = Utf8               SyncMonitorDemo.java
  #22 = NameAndType        #7:#8          // "<init>":()V
  #23 = Utf8               java/lang/Object
  #24 = Class              #30            // java/lang/System
  #25 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;
  #26 = Utf8               locking...
  #27 = Class              #33            // java/io/PrintStream
  #28 = NameAndType        #34:#35        // println:(Ljava/lang/String;)V
  #29 = Utf8               cn/tao/king/juc/execises1/SyncMonitorDemo
  #30 = Utf8               java/lang/System
  #31 = Utf8               out
  #32 = Utf8               Ljava/io/PrintStream;
  #33 = Utf8               java/io/PrintStream
  #34 = Utf8               println
  #35 = Utf8               (Ljava/lang/String;)V
{public cn.tao.king.juc.execises1.SyncMonitorDemo();
    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 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/tao/king/juc/execises1/SyncMonitorDemo;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #2                  // class java/lang/Object
         3: dup
         4: invokespecial #1                  // Method java/lang/Object."<init>":()V
         7: astore_1
         8: aload_1
         9: dup
        10: astore_2
        11: monitorenter
        12: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        15: ldc           #4                  // String locking...
        17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        20: aload_2
        21: monitorexit
        22: goto          30
        25: astore_3
        26: aload_2
        27: monitorexit
        28: aload_3
        29: athrow
        30: return
      Exception table:
         from    to  target type
            12    22    25   any
            25    28    25   any
      LineNumberTable:
        line 5: 0
        line 6: 8
        line 7: 12
        line 8: 20
        line 9: 30
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      31     0  args   [Ljava/lang/String;
            8      23     1     o   Ljava/lang/Object;
}
SourceFile: "SyncMonitorDemo.java"

javap是 JDK 自带的一个反汇编命令。你能够疏忽其余不必要的信息,间接在后果中找到上面这段代码:

11: monitorenter
12: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc           #4                  // String locking...
17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_2
21: monitorexit

看到 monitorentermonitorexit指令,置信智慧的你曾经看穿所有。

以上就是文本的全部内容,祝贺你又上了一颗星✨

夫子的试炼

  • 写一段蕴含 synchronized 关键字的代码,应用 javap 命令察看后果。

对于作者

关注公众号【庸人技术笑谈】,获取及时文章更新。记录平凡人的技术故事,分享有品质(尽量)的技术文章,偶然也聊聊生存和现实。不贩卖焦虑,不抛售课程。

如果本文对你有帮忙,欢送 点赞 关注

正文完
 0