
并发编程:共享模型之管程
什么是管程(Monitor)
管程(Monitor)是一种并发编程的模型和技术,用于解决多线程之间的互斥访问和条件等待的问题。它是由荷兰计算机科学家 Edsger Dijkstra 在 1971 年提出的一种同步机制。
管程提供了一种方式让多个线程能够协调彼此的执行,确保在任意时刻只有一个线程可以访问共享资源,从而避免了线程间的竞争条件(Race Condition)和数据不一致的问题。
管程通常由以下几个要素组成:
互斥锁(Mutex):用于实现对共享资源的互斥访问,保证同一时刻只有一个线程可以进入管程进行操作。
条件变量(Condition Variable):用于实现线程间的条件等待和通知机制。线程可以在条件不满足的情况下等待,并在条件满足时被唤醒继续执行。
入口队列(Entry Queue):用于存放等待访问资源的线程队列。
管程内部方法:包括对资源的操作和对条件变量的操作等。
通过管程,可以将对共享资源的访问限制在管程的范围内,线程在进入管程之前需要获得管程的互斥锁,如果资源被占用,线程将进入入口队列等待;当某个线程完成对共享资源的操作后,会释放互斥锁并唤醒等待队列中的某个线程继续执行。
管程的主要优点是提供了一种高层次的抽象和封装,简化了多线程编程的复杂性,提供了一种结构化的方式来管理线程之间的同步和协作。它可以有效地避免死锁(Deadlock)和饥饿(Starvation)等并发编程中常见的问题。
举例
在多线程中有A、B两个线程同时需要修改某一个共享资源,线程A从内存中读取共享资源,但还未来得及提交修改,或者处于休眠状态;同时,线程B获取到同一个共享资源并进行了修改,然后将修改后的值放回内存中。接着,当线程A继续执行并将它的修改放回内存时,它会覆盖线程B之前的修改,从而导致最终的结果不一致
上述例子也就体现了,线程A和线程B同时竞争修改共享资源,其操作顺序可能会导致不一致的结果,因此我们可以采用同步机制,管程或锁机制来确保只有一个线程可以修改资源
Java体现资源争抢
以上的结果可能为负数、正数或0,因为Java中对静态变量的自增或自减操作并不是原子性操作
临界区 Critical Section
一个程序运行多个线程本身是没有问题的
问题出在多个线程访问共享资源
多个线程读共享资源其实也没有问题
在多个线程对共享资源读写操作时发生指令交错,就会出现问题
一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区 例如,下面代码中的临界区
竞态条件 Race Condition
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件
synchronized
为了避免临界区的竞态条件发生,有多种手段可以达到目的。
阻塞式的解决方案:synchronized,Lock
非阻塞式的解决方案:原子变量
synchronized 即俗称的【对象锁】,它采用互斥的方式让同一 时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换(也就是线程切换)
注意
虽然 java 中互斥和同步都可以采用 synchronized 关键字来完成,但它们还是有区别的:
互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码
同步是由于线程执行的先后、顺序不同、需要一个线程等待其它线程运行到某个点
语法
解决
方法上的 synchronized
Monitor概念
Java 对象头
普通对象
数组对象
其中 Mark Word 结构为
64位虚拟机Mark Word
上图所示,其实Monitor就是充当一个锁,只要是同一个对象,都会跟同一个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 状态的线程,后面讲 wait-notify 时会分析
注意:
synchronized 必须是进入同一个对象的 monitor 才有上述的效果
不加 synchronized 的对象不会关联监视器,不遵从以上规则
Monitor原理之synchronize
- 感谢你赐予我前进的力量