Monitor概念

本文详细介绍了Java对象头在32位虚拟机中的结构,包括普通对象和数组对象的区别。重点讲解了MarkWord和Monitor的关系,当使用synchronized同步时,对象头的MarkWord会指向Monitor。Monitor中包含Owner、EntryList和WaitSet,用于线程同步和等待。文章还强调了synchronized关键字对于Monitor的重要性以及其工作原理。

Java对象头

以32位虚拟机为例

普通对象

数组对象

其中Mark Word结构为

Monitor

Monitor被翻译为监视器或者管程

每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Word中就被设置指向Monitor的指针

Monitor结构如下

  • 刚开始Monitor中Owner为null
  • 当Thread-2执行synchronized(obj)就会将Monitor的所有者Owner置为Thread-2,Monitor中只能有一个Owner
  • 在Thread-2上锁的过程中,如果Thread-3、Thread-4、Thread-5也来执行synchronized(obj),就会进入EntryList BLOCKED
  • Thread-2执行完同步代码块的内容,然后唤醒EntryList中等待的线程来竞争锁,竞争是非公平的
  • 图中WaitSet中的Thread-0、Thread-1是之前获得过锁,但是条件不满足进入WAITING状态的线程

注意:

  • synchronized必须是进入同一个对象的monitor才有上述的效果
  • 不加synchronized的对象不会关联监视器,不遵从以上规则
### JavaMonitor概念及作用 #### 什么是 MonitorMonitor 是一种同步机制,用于协调多个线程对共享资源的访问。在 Java 中,`synchronized` 关键字的背后依赖于 Monitor 来实现线程间的互斥和协作[^1]。 每个 Java 对象都有一个与之关联的 Monitor 对象。当某个线程试图进入由 `synchronized` 保护的方法或代码块时,它实际上是在尝试获取该对象对应的 Monitor 锁[^5]。如果此时没有其他线程持有这个锁,则当前线程可以直接获得并继续执行;如果有另一个线程已经持有了此锁,则新来的线程会被加入到阻塞队列 (EntryList),直到前一线程释放锁为止[^3]。 #### Monitor 的组成 Monitor 主要包含以下几个部分: - **Owner**: 表示当前拥有锁的线程。只有成为 Owner 的线程才能修改受保护的数据结构。 - **EntryList**: 阻塞队列,存储那些正在等待获取锁的线程。这些线程因为无法立即得到锁而暂时挂起在这里。 - **WaitSet**: 等待集合,保存调用了 `wait()` 方法后放弃锁并处于休眠状态下的线程们。它们会在特定条件下被唤醒并通过重新竞争来争取再次占有锁的机会。 #### 基本操作 除了简单的加解锁之外,Monitor 还支持更复杂的线程间通信功能——即基于条件变量的操作: - `wait()`: 让当前持有锁的线程暂停运行并将自己放入 WaitSet 当中去,同时允许别的线程有机会取得相同的锁。 - `notify() / notifyAll()`: 被用来通知某一个或者全部处在 Waiting Set 上面的线程醒来准备抢夺锁资源[^2]。 以下是利用 synchronized 实现的一个简单例子展示如何使用上述提到的功能: ```java public class Counter { private int count; public synchronized void increment() throws InterruptedException { while (count >= 5) { // 如果计数值达到上限则让出CPU时间片 wait(); // 将当前线程置于等待集(wait set) } this.count++; System.out.println(Thread.currentThread().getName() + ": " + this.count); notifyAll(); // 唤醒所有等待中的线程让他们有机会重新争夺锁 } public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Thread t1 = new Thread(() -> { try { for(int i=0;i<10;i++) counter.increment(); } catch (InterruptedException e){} }); Thread t2 = new Thread(() -> { try { for(int i=0;i<10;i++) counter.increment(); } catch (InterruptedException e){} }); t1.start(); t2.start(); t1.join(); t2.join(); } } ``` 在这个程序里我们创建了一个名为Counter类代表计数器,并且有两个不同的线程t1,t2分别对该实例进行增一操作。每当其中一个线程发现计数超过了预设的最大值就会主动调用wait方法把自己放进waiting pool里面去从而使得另外一条线程能够顺利拿到锁进而改变数据的状态。一旦满足一定条件之后又会通过notify all的方式告知其它可能存在的候选者现在可以试着看看能不能成功夺取那个宝贵的锁啦! ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值