美文网首页
调试监视器锁

调试监视器锁

作者: buzzerrookie | 来源:发表于2019-03-15 15:17 被阅读0次

为了更深入地理解监视器锁,本文使用gdb调试Hotspot虚拟机展示监视器锁获取与释放的部分执行过程。

调试准备

为了获得Thread类对象的线程ID,内核线程ID与Linux线程ID这三者之间的对应关系,我在hotspot/src/share/vm/runtime/thread.cpp的JavaThread::run函数起始处增加了一行代码,可以按顺序输出JVM中的线程指针、Thread类对象的线程ID、该对象对应的内核线程ID和Linux线程ID。

fprintf(stderr, "JavaThread address: %lx, thread id in Java: %d, LWP: %d, pthread tid: %lx\n", this, java_lang_Thread::thread_id(this->threadObj()), this->_osthread->thread_id(), this->_osthread->pthread_id());

获取监视器锁

获取监视器锁的实验代码如下:

public class MonitorEnter extends Thread {
    private final Object lock;

    public MonitorEnter(Object lock) {
        this.lock = lock;
    }

    public void run() {
        synchronized (lock) {
            try {
                while (true) {
                    Thread.sleep(1000);
                    System.out.println("Thread name: " + Thread.currentThread().getName() + " id: " +
                            Thread.currentThread().getId());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("main thread id: " + Thread.currentThread().getId());
        Object lock = new Object();
        Thread t1 = new MonitorEnter(lock);
        t1.setName("t1");
        System.out.println("t1 id: " + t1.getId());
        Thread t2 = new MonitorEnter(lock);
        t2.setName("t2");
        System.out.println("t2 id: " + t2.getId());
        Thread t3 = new MonitorEnter(lock);
        t3.setName("t3");
        System.out.println("t3 id: " + t3.getId());
        Thread t4 = new MonitorEnter(lock);
        t4.setName("t4");
        System.out.println("t4 id: " + t4.getId());
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

gdb调试的交互过程如下:

[suntao@CentOS-VM ~]$ cd openjdk8/build/linux-x86_64-normal-server-slowdebug/jdk/bin/
[suntao@CentOS-VM bin]$ gdb ./java
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/suntao/openjdk8/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java...done.
(gdb) b /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:546
No source file named /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (/home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:546) pending.
(gdb) r -cp /home/suntao/test/ MonitorEnter
Starting program: /home/suntao/openjdk8/build/linux-x86_64-normal-server-slowdebug/jdk/bin/./java -cp /home/suntao/test/ MonitorEnter
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7ffff7feb700 (LWP 11644)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7feb700 (LWP 11644)]
0x00007fffe10002b4 in ?? ()
Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7_6.3.x86_64 libgcc-4.8.5-36.el7.x86_64 libstdc++-4.8.5-36.el7.x86_64
(gdb) c
Continuing.
[New Thread 0x7ffff4475700 (LWP 11645)]
[New Thread 0x7ffff4374700 (LWP 11646)]
[New Thread 0x7fffde08b700 (LWP 11647)]
[New Thread 0x7fffddf8a700 (LWP 11648)]
JavaThread address: 7ffff0106000, thread id in Java: 2, LWP: 11648, pthread tid: 7fffddf8a700
[New Thread 0x7fffdde89700 (LWP 11649)]
JavaThread address: 7ffff010b800, thread id in Java: 3, LWP: 11649, pthread tid: 7fffdde89700
[New Thread 0x7fffddd88700 (LWP 11650)]
JavaThread address: 7ffff015b000, thread id in Java: 4, LWP: 11650, pthread tid: 7fffddd88700
[New Thread 0x7fffddc87700 (LWP 11651)]
JavaThread address: 7ffff015d000, thread id in Java: 5, LWP: 11651, pthread tid: 7fffddc87700
[New Thread 0x7fffddb86700 (LWP 11652)]
JavaThread address: 7ffff0160800, thread id in Java: 6, LWP: 11652, pthread tid: 7fffddb86700
[New Thread 0x7fffdda85700 (LWP 11653)]
[New Thread 0x7fffdd984700 (LWP 11654)]
JavaThread address: 7ffff016c000, thread id in Java: 7, LWP: 11653, pthread tid: 7fffdda85700
main thread id: 1
t1 id: 8
t2 id: 9
t3 id: 10
t4 id: 11
[New Thread 0x7fffdd883700 (LWP 11655)]
JavaThread address: 7ffff01a9000, thread id in Java: 8, LWP: 11655, pthread tid: 7fffdd883700
[New Thread 0x7fffdd782700 (LWP 11656)]
JavaThread address: 7ffff01ab000, thread id in Java: 9, LWP: 11656, pthread tid: 7fffdd782700
[Switching to Thread 0x7fffdd782700 (LWP 11656)]

Breakpoint 1, ObjectMonitor::EnterI (this=0x7fffc8006368, __the_thread__=0x7ffff01ab000)
    at /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:546
546     ObjectWaiter node(Self) ;
(gdb) p _owner
$1 = (void * volatile) 0x7fffdd882780
(gdb) p OwnerIsThread
$2 = 0
(gdb) p _cxq
$3 = (ObjectWaiter * volatile) 0x0
(gdb) p _EntryList
$4 = (ObjectWaiter * volatile) 0x0
(gdb) c
Continuing.
[New Thread 0x7fffdd681700 (LWP 11657)]
Thread name: t1 id: 8
JavaThread address: 7ffff01ad000, thread id in Java: 10, LWP: 11657, pthread tid: 7fffdd681700
[New Thread 0x7fffdd580700 (LWP 11658)]
JavaThread address: 7ffff01af800, thread id in Java: 11, LWP: 11658, pthread tid: 7fffdd580700
[Switching to Thread 0x7fffdd580700 (LWP 11658)]

Breakpoint 1, ObjectMonitor::EnterI (this=0x7fffc8006368, __the_thread__=0x7ffff01af800)
    at /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:546
546     ObjectWaiter node(Self) ;
(gdb) p _owner
$5 = (void * volatile) 0x7fffdd882780
(gdb) p OwnerIsThread
$6 = 0
(gdb) p _cxq
$7 = (ObjectWaiter * volatile) 0x7fffdd781480
(gdb) p _cxq->_thread->_osthread->_thread_id
$8 = 11656
(gdb) p _cxq->_next
$9 = (ObjectWaiter * volatile) 0x0
(gdb) c
Continuing.
Thread name: t1 id: 8
[Switching to Thread 0x7fffdd681700 (LWP 11657)]

Breakpoint 1, ObjectMonitor::EnterI (this=0x7fffc8006368, __the_thread__=0x7ffff01ad000)
    at /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:546
546     ObjectWaiter node(Self) ;
(gdb) p _owner
$10 = (void * volatile) 0x7fffdd882780
(gdb) p OwnerIsThread
$11 = 0
(gdb) p _cxq
$12 = (ObjectWaiter * volatile) 0x7fffdd57f380
(gdb) p _cxq->_thread->_osthread->_thread_id
$13 = 11658
(gdb) p _cxq->_next->_thread->_osthread->_thread_id
$14 = 11656
(gdb) p _cxq->_next
$15 = (ObjectWaiter * volatile) 0x7fffdd781480
(gdb) p _cxq->_next->_next
$16 = (ObjectWaiter * volatile) 0x0
(gdb) n
547     Self->_ParkEvent->reset() ;
(gdb)
Thread name: t1 id: 8
548     node._prev   = (ObjectWaiter *) 0xBAD ;
(gdb)
549     node.TState  = ObjectWaiter::TS_CXQ ;
(gdb)
557         node._next = nxt = _cxq ;
(gdb)
558         if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
(gdb)
593     if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
(gdb) p _cxq
$17 = (ObjectWaiter * volatile) 0x7fffdd680400
(gdb) p _cxq->_thread->_osthread->_thread_id
$18 = 11657
(gdb) p _cxq->_next
$19 = (ObjectWaiter * volatile) 0x7fffdd57f380
(gdb) p _cxq->_next->_thread->_osthread->_thread_id
$20 = 11658
(gdb) p _cxq->_next->_next
$21 = (ObjectWaiter * volatile) 0x7fffdd781480
(gdb) p _cxq->_next->_next->_thread->_osthread->_thread_id
$22 = 11656
(gdb) p _cxq->_next->_next->_next
$23 = (ObjectWaiter * volatile) 0x0
(gdb) c
Continuing.
Thread name: t1 id: 8
Thread name: t1 id: 8
Thread name: t1 id: 8
^C
Program received signal SIGINT, Interrupt.
[Switching to Thread 0x7ffff7fec740 (LWP 11640)]
0x00007ffff7bc7f47 in pthread_join () from /lib64/libpthread.so.0
(gdb)

上述实验创建的线程如下:

线程名称 Thread类的getId方法返回值 内核线程ID JVM中的线程指针
t1 8 11655 0x7ffff01a9000
t2 9 11656 0x7ffff01ab000
t3 10 11657 0x7ffff01ad000
t4 11 11658 0x7ffff01af800
  • 线程t1首先获得了监视器锁,由于是从轻量级锁膨胀成监视器锁,因此_owner是轻量级锁记录的指针,OwnerIsThread是0印证了这一点;
  • 注意看断点的参数,如ObjectMonitor::EnterI (this=0x7fffc8006368, __the_thread__=0x7ffff01ab000)__the_thread__变量正是t2线程,这是t2尝试获得监视器的过程,其他线程同理;
  • Java中的synchronized关键字(二)一文提到在EnterI函数中若自旋失败,则参数线程被包装成ObjectWaiter并加入_cxq队首,调试输出表明_cxq链表的形式是t3 -> t4 -> t2 -> NULL,这验证了该文论述的正确性。

释放监视器锁

释放监视器锁的实验代码如下:

public class MonitorExit extends Thread {
    private final Object lock;

    public MonitorExit(Object lock) {
        this.lock = lock;
    }

    public void run() {
        synchronized (lock) {
            try {
                Thread.sleep(2000);
                System.out.println("Thread name: " + Thread.currentThread().getName() + " id: " +
                        Thread.currentThread().getId());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("main thread id: " + Thread.currentThread().getId());
        Object lock = new Object();
        Thread t1 = new MonitorExit(lock);
        t1.setName("t1");
        System.out.println("t1 id: " + t1.getId());
        Thread t2 = new MonitorExit(lock);
        t2.setName("t2");
        System.out.println("t2 id: " + t2.getId());
        Thread t3 = new MonitorExit(lock);
        t3.setName("t3");
        System.out.println("t3 id: " + t3.getId());
        Thread t4 = new MonitorExit(lock);
        t4.setName("t4");
        System.out.println("t4 id: " + t4.getId());
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

gdb调试的交互过程如下:

[suntao@CentOS-VM ~]$ cd openjdk8/build/linux-x86_64-normal-server-slowdebug/jdk/bin/
[suntao@CentOS-VM bin]$ gdb ./java
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/suntao/openjdk8/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java...done.
(gdb) b /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:958
No source file named /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (/home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:958) pending.
(gdb) r -cp /home/suntao/test/ MonitorExit
Starting program: /home/suntao/openjdk8/build/linux-x86_64-normal-server-slowdebug/jdk/bin/./java -cp /home/suntao/test/ MonitorExit
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7ffff7feb700 (LWP 11705)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7feb700 (LWP 11705)]
0x00007fffe10002b4 in ?? ()
Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7_6.3.x86_64 libgcc-4.8.5-36.el7.x86_64 libstdc++-4.8.5-36.el7.x86_64
(gdb) c
Continuing.
[New Thread 0x7ffff4475700 (LWP 11706)]
[New Thread 0x7ffff4374700 (LWP 11707)]
[New Thread 0x7fffde08b700 (LWP 11708)]
[New Thread 0x7fffddf8a700 (LWP 11709)]
JavaThread address: 7ffff0106000, thread id in Java: 2, LWP: 11709, pthread tid: 7fffddf8a700
[New Thread 0x7fffdde89700 (LWP 11710)]
JavaThread address: 7ffff010b800, thread id in Java: 3, LWP: 11710, pthread tid: 7fffdde89700
[New Thread 0x7fffddd88700 (LWP 11711)]
JavaThread address: 7ffff015b000, thread id in Java: 4, LWP: 11711, pthread tid: 7fffddd88700
[New Thread 0x7fffddc87700 (LWP 11712)]
JavaThread address: 7ffff015d000, thread id in Java: 5, LWP: 11712, pthread tid: 7fffddc87700
[New Thread 0x7fffddb86700 (LWP 11713)]
JavaThread address: 7ffff0160800, thread id in Java: 6, LWP: 11713, pthread tid: 7fffddb86700
[New Thread 0x7fffdda85700 (LWP 11714)]
JavaThread address: 7ffff018d000, thread id in Java: 7, LWP: 11714, pthread tid: 7fffdda85700
[New Thread 0x7fffdd984700 (LWP 11715)]
main thread id: 1
t1 id: 8
t2 id: 9
t3 id: 10
t4 id: 11
[New Thread 0x7fffdd883700 (LWP 11716)]
JavaThread address: 7ffff01b9000, thread id in Java: 8, LWP: 11716, pthread tid: 7fffdd883700
[New Thread 0x7fffdd782700 (LWP 11717)]
JavaThread address: 7ffff01bb000, thread id in Java: 9, LWP: 11717, pthread tid: 7fffdd782700
[New Thread 0x7fffdd681700 (LWP 11718)]
JavaThread address: 7ffff01bd000, thread id in Java: 10, LWP: 11718, pthread tid: 7fffdd681700
[New Thread 0x7fffdd580700 (LWP 11719)]
JavaThread address: 7ffff01bf800, thread id in Java: 11, LWP: 11719, pthread tid: 7fffdd580700
Thread name: t1 id: 8
[Switching to Thread 0x7fffdd883700 (LWP 11716)]

Breakpoint 1, ObjectMonitor::exit (this=0x7fffc8002218, not_suspended=true, __the_thread__=0x7ffff01b9000)
    at /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:958
958    if (THREAD != _owner) {
(gdb) p _owner
$1 = (void * volatile) 0x7fffdd882500
(gdb) p OwnerIsThread
$2 = 0
(gdb) p _cxq
$3 = (ObjectWaiter * volatile) 0x7fffdd57f600
(gdb) p _cxq->_thread->_osthread->_thread_id
$4 = 11719
(gdb) p _cxq->_next
$5 = (ObjectWaiter * volatile) 0x7fffdd680580
(gdb) p _cxq->_next->_thread->_osthread->_thread_id
$6 = 11718
(gdb) p _cxq->_next->_next
$7 = (ObjectWaiter * volatile) 0x7fffdd781300
(gdb) p _cxq->_next->_next->_thread->_osthread->_thread_id
$8 = 11717
(gdb) p _cxq->_next->_next->_next
$9 = (ObjectWaiter * volatile) 0x0
(gdb) p _EntryList
$10 = (ObjectWaiter * volatile) 0x0
(gdb) n
959      if (THREAD->is_lock_owned((address) _owner)) {
(gdb)
964        assert (_recursions == 0, "invariant") ;
(gdb)
965        _owner = THREAD ;
(gdb)
966        _recursions = 0 ;
(gdb)
967        OwnerIsThread = 1 ;
(gdb) b 1103
Breakpoint 2 at 0x7ffff68e0b01: file /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp, line 1103.
(gdb) c
Continuing.

Breakpoint 2, ObjectMonitor::exit (this=0x7fffc8002218, not_suspended=true, __the_thread__=0x7ffff01b9000)
    at /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:1103
1103          if (QMode == 2 && _cxq != NULL) {
(gdb) p Knob_QMode
$11 = 0
(gdb) p _cxq
$12 = (ObjectWaiter * volatile) 0x7fffdd57f600
(gdb) p _EntryList
$13 = (ObjectWaiter * volatile) 0x0
(gdb) n
1114          if (QMode == 3 && _cxq != NULL) {
(gdb)
1152          if (QMode == 4 && _cxq != NULL) {
(gdb)
1187          w = _EntryList  ;
(gdb)
1188          if (w != NULL) {
(gdb) p w
$14 = (ObjectWaiter *) 0x0
(gdb) n
1207          w = _cxq ;
(gdb) p _cxq
$15 = (ObjectWaiter * volatile) 0x7fffdd57f600
(gdb) n
1208          if (w == NULL) continue ;
(gdb) p w
$16 = (ObjectWaiter *) 0x7fffdd57f600
(gdb) n
1214              assert (w != NULL, "Invariant") ;
(gdb)
1215              ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
(gdb) n
1216              if (u == w) break ;
(gdb)
1221          assert (w != NULL              , "invariant") ;
(gdb)
1222          assert (_EntryList  == NULL    , "invariant") ;
(gdb)
1233          if (QMode == 1) {
(gdb)
1252             _EntryList = w ;
(gdb)
1253             ObjectWaiter * q = NULL ;
(gdb) p _EntryList
$17 = (ObjectWaiter * volatile) 0x7fffdd57f600
(gdb) n
1255             for (p = w ; p != NULL ; p = p->_next) {
(gdb)
1256                 guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
(gdb)
1257                 p->TState = ObjectWaiter::TS_ENTER ;
(gdb)
1258                 p->_prev = q ;
(gdb)
1259                 q = p ;
(gdb)
1255             for (p = w ; p != NULL ; p = p->_next) {
(gdb)
1256                 guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
(gdb)
1257                 p->TState = ObjectWaiter::TS_ENTER ;
(gdb)
1258                 p->_prev = q ;
(gdb)
1259                 q = p ;
(gdb)
1255             for (p = w ; p != NULL ; p = p->_next) {
(gdb)
1256                 guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
(gdb)
1257                 p->TState = ObjectWaiter::TS_ENTER ;
(gdb)
1258                 p->_prev = q ;
(gdb)
1259                 q = p ;
(gdb)
1255             for (p = w ; p != NULL ; p = p->_next) {
(gdb)
1269          if (_succ != NULL) continue;
(gdb)
1271          w = _EntryList  ;
(gdb)
1272          if (w != NULL) {
(gdb)
1273              guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
(gdb)
1274              ExitEpilog (Self, w) ;
(gdb) p w->_thread->_osthread->_thread_id
$18 = 11719
(gdb) c
Continuing.
[Thread 0x7fffdd883700 (LWP 11716) exited]
Thread name: t4 id: 11
[Switching to Thread 0x7fffdd580700 (LWP 11719)]

Breakpoint 1, ObjectMonitor::exit (this=0x7fffc8002218, not_suspended=true, __the_thread__=0x7ffff01bf800)
    at /home/suntao/openjdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp:958
958    if (THREAD != _owner) {
(gdb) p _owner
$19 = (void * volatile) 0x7ffff01bf800
(gdb)

上述实验创建的线程如下:

线程名称 Thread类的getId方法返回值 内核线程ID JVM中的线程指针
t1 8 11716 0x7ffff01b9000
t2 9 11717 0x7ffff01bb000
t3 10 11718 0x7ffff01bd000
t4 11 11719 0x7ffff01bf800
  • 第一个断点暂停时参数__the_thread__是0x7ffff01b9000,这是线程t1的指针,此时t1正释放监视器锁,由于获得监视器锁时是从轻量级锁膨胀成监视器锁,因此_owner是轻量锁记录的指针,OwnerIsThread是0;
  • cxq队列是t4 -> t3 -> t2 -> NULL,_EntryList为空;
  • 第二个断点暂停时Knob_QMode是默认值0,cxq链表不为空但EntryList链表为空,因此cxq链表成为EntryList链表,不需要反转,然后新EntryList链表中的第一个线程被唤醒,即t4获得了监视器锁,这验证了Java中的synchronized关键字(三)一文论述的正确性。

相关文章

  • 调试监视器锁

    为了更深入地理解监视器锁,本文使用gdb调试Hotspot虚拟机展示监视器锁获取与释放的部分执行过程。 调试准备 ...

  • synchronized原理

    synchronized是一种内置锁/监视器锁Java中每个对象都有一个内置锁(监视器,也可以理解成锁标记),而s...

  • 第二十七章 使用系统监视器 - 调试监视器类

    第二十七章 使用系统监视器 - 调试监视器类 此子菜单可让管理系统调试。 调试监控器类增加了捕获用户定义的应用程序...

  • Java 并发编程:轻量级锁和偏向锁详解

    问题背景 Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是...

  • java关键字之Synchronized

    Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层...

  • java中的锁

    Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层...

  • 高并发编程基础1(bjsxt学习笔记)

    并发编程大概主要涉及三个概念: 多线程、监视器、对象。 其中监视器也可以叫做锁。 (1)怎么给对象加监视器? 例如...

  • 2019大厂面试存疑

    Java相关 Java实现的锁有哪些synchornized实现的监视器锁、ReentrantLock、ReadW...

  • 咀嚼Lock和Synchronized锁

    1.Synchronized锁 底层是monitor监视器,每一个对象再创建的时候都会常见一个monitor监视器...

  • JVM锁优化

    synchronized重量级锁 synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现...

网友评论

      本文标题:调试监视器锁

      本文链接:https://www.haomeiwen.com/subject/olqkmqtx.html