本文是《深入理解多线程系列文章》的第四篇。点击查看原文,阅读该系列所有文章。

在深入理解多线程(一)——Synchronized的实现原理中介绍过关于Synchronize的实现原理,无论是同步方法还是同步代码块,无论是ACC_SYNCHRONIZED还是monitorenter、monitorexit都是基于Monitor实现的,那么这篇来介绍下什么是Monitor

操作系统中的管程

如果你在大学学习过操作系统,你可能还记得管程(monitors)在操作系统中是很重要的概念。同样Monitor在java同步机制中也有使用。

管程 (英语:Monitors,也称为监视器) 是一种程序结构,结构内的多个子程序(对象或模块)形成的多个工作线程互斥访问共享资源。这些共享资源一般是硬件设备或一群变量。管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。 管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。

Java线程同步相关的Moniter

在多线程访问共享资源的时候,经常会带来可见性和原子性的安全问题。为了解决这类线程安全的问题,Java提供了同步机制、互斥锁机制,这个机制保证了在同一时刻只有一个线程能访问共享资源。这个机制的保障来源于监视锁Monitor,每个对象都拥有自己的监视锁Monitor。

先来举个例子,然后我们在上源码。我们可以把监视器理解为包含一个特殊的房间的建筑物,这个特殊房间同一时刻只能有一个客人(线程)。这个房间中包含了一些数据和代码。

如果一个顾客想要进入这个特殊的房间,他首先需要在走廊(Entry Set)排队等待。调度器将基于某个标准(比如 FIFO)来选择排队的客户进入房间。如果,因为某些原因,该客户客户暂时因为其他事情无法脱身(线程被挂起),那么他将被送到另外一间专门用来等待的房间(Wait Set),这个房间的可以可以在稍后再次进入那件特殊的房间。如上面所说,这个建筑屋中一共有三个场所。

总之,监视器是一个用来监视这些线程进入特殊的房间的。他的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码。

Monitor其实是一种同步工具,也可以说是一种同步机制,它通常被描述为一个对象,主要特点是:

对象的所有方法都被“互斥”的执行。好比一个Monitor只有一个运行“许可”,任一个线程进入任何一个方法都需要获得这个“许可”,离开时把许可归还。通常提供singal机制:允许正持有“许可”的线程暂时放弃“许可”,等待某个谓词成真(条件变量),而条件成立后,当前进程可以“通知”正在等待这个条件变量的线程,让他可以重新去获得运行许可。

监视器的实现

在Java虚拟机(HotSpot)中,Monitor是基于C++实现的,由ObjectMonitor实现的,其主要数据结构如下:

 ObjectMonitor() { _header = NULL; _count = 0; _waiters = 0, _recursions = 0; _object = NULL; _owner = NULL; _WaitSet = NULL; _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; FreeNext = NULL ; _EntryList = NULL ; _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; }

源码地址:objectMonitor.hpp

ObjectMonitor中有几个关键属性:

_owner:指向持有ObjectMonitor对象的线程_WaitSet:存放处于wait状态的线程队列_EntryList:存放处于等待锁block状态的线程队列_recursions:锁的重入次数_count:用来记录该线程获取锁的次数

当多个线程同时访问一段同步代码时,首先会进入_EntryList队列中,当某个线程获取到对象的monitor后进入_Owner区域并把monitor中的_owner变量设置为当前线程,同时monitor中的计数器_count加1。即获得对象锁。

若持有monitor的线程调用wait()方法,将释放当前持有的monitor,_owner变量恢复为null,_count自减1,同时该线程进入_WaitSet集合中等待被唤醒。若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。如下图所示

ObjectMonitor类中提供了几个方法:

获得锁

释放锁

除了enter和exit方法以外,objectMonitor.cpp中还有

void wait(jlong millis, bool interruptable, TRAPS);void notify(TRAPS);void notifyAll(TRAPS);

等方法。

总结

上面介绍的就是HotSpot虚拟机中Moniter的的加锁以及解锁的原理。

通过这篇文章我们知道了sychronized加锁的时候,会调用objectMonitor的enter方法,解锁的时候会调用exit方法。事实上,只有在JDK1.6之前,synchronized的实现才会直接调用ObjectMonitor的enter和exit,这种锁被称之为重量级锁。为什么说这种方式操作锁很重呢?

  • Java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统的帮忙,这就要从用户态转换到核心态,因此状态转换需要花费很多的处理器时间,对于代码简单的同步块(如被synchronized修饰的get 或set方法)状态转换消耗的时间有可能比用户代码执行的时间还要长,所以说synchronized是java语言中一个重量级的操纵。

所以,在JDK1.6中出现对锁进行了很多的优化,进而出现轻量级锁偏向锁锁消除适应性自旋锁锁粗化(自旋锁在1.4就有 只不过默认的是关闭的,jdk1.6是默认开启的),这些操作都是为了在线程之间更高效的共享数据 ,解决竞争问题。后面的文章会继续介绍这几种锁以及他们之间的关系。

原文地址:https://dwz.cn/m8arDgba
作者: Hollis

操作系统锁的实现方法有哪几种_深入理解多线程(四)——Moniter的实现原理...相关推荐

  1. 操作系统锁的实现方法有哪几种_「从入门到放弃-Java」并发编程-锁-synchronized...

    简介 上篇[从入门到放弃-Java]并发编程-线程安全中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全. synchronized是java提供的一种内置的锁机制.通过synchroni ...

  2. 操作系统锁的实现方法有哪几种_一文带你彻底了解同步和锁的本质

    谈到锁,离不开多线程,或者进程间的通信.为了更好地从底层原理去了解锁的机制,形成体系化的知识,这篇文章我会从进程间通信底层原理说起,然后介绍一下Java中各种线程通信的实现机制,最后做一个系统的总结. ...

  3. 操作系统锁的实现方法有哪几种_java 偏向锁、轻量级锁及重量级锁synchronized原理...

    Java对象头与Monitor java对象头是实现synchronized的锁对象的基础,synchronized使用的锁对象是存储在Java对象头里的. 对象头包含两部分:Mark Word 和 ...

  4. 操作系统锁的实现方法有哪几种_Java并发之Monitor实现

    Java并发之Monitor实现 可能在synchronized关键字的实现原理中,你已经知道了它的底层是使用Monitor的相关指令来实现的,但是还不清楚Monitor的具体细节.本文将让你彻底Mo ...

  5. python excel操作单元格_python 操作excel表格的方法

    说明:由于公司oa暂缺,人事妹子在做考勤的时候,需要通过几个excel表格去交叉比对员工是否有旷工或迟到,工作量大而且容易出错. 这时候it屌丝的机会来啦,花了一天时间给妹子撸了一个自动化脚本. 1. ...

  6. mac php 连接mysql数据库_Mac环境下php操作mysql数据库的方法分享

    Mac环境下php操作mysql数据库的方法分享 今天在mac上搭建好了php的环境,我们就把php操作mysql数据库的方法分享给大家,有需要的小伙伴参考下. Mac本地环境搭建 在Mac系统,我们 ...

  7. Oracle数据库的impdp导入操作以及dba_directories使用方法

    Oracle数据库的impdp导入操作以及dba_directories使用方法 今天从同事那里拿到了导出的dmp文件,当导入时发现了很多问题,记下来以免以后忘记,以下是本人的操作过程: 1.首先是创 ...

  8. c# mysql executescalar_C# 操作MySQL数据库, ExecuteScalar()方法执行T-SQL语句, COUNT(*), 统计数据...

    C# 操作My SQL数据库需要引用"MySql.Data", 可通过两种方式获取. 1.从NuGet下载"Install-Package MySql.Data -Ver ...

  9. 误操作数据库的一个方法

    1 问题数据库 备份日志 backup log InterCreditAVDb to disk='E:\黑名单系统\数据库\log1.bak' 2 还原最新完整备份的数据 use master RES ...

  10. mac php 连接mysql数据库_Mac环境下php操作mysql数据库的方法分享_PHP教程

    Mac环境下php操作mysql数据库的方法分享 今天在mac上搭建好了php的环境,我们就把php操作mysql数据库的方法分享给大家,有需要的小伙伴参考下. Mac本地环境搭建 在Mac系统,我们 ...

最新文章

  1. 求助关于系统日志的解决方案
  2. TVS 管性能及选型总结
  3. 阿里的 RocketMQ 如何让双十一峰值之下0故障
  4. javascript 无法修改 数组中对象_如何使用JavaScript中的Date对象
  5. oracle 自增字段设置
  6. python编入小学教材_之前纳入小学教材的Python,现在真能学会了!
  7. 虚拟化实战——存储(二)
  8. selenium之qq邮箱登录-发邮件
  9. php 统计一个月工作日,php – 使用strtotime在一个月内获得第一个工作日
  10. No.44-VulnHub-Pegasus: 1-Walkthrough渗透学习
  11. python爬虫 scrapy 爬取腾讯招聘
  12. win10 双屏显示 鼠标可以从主屏幕左侧滑入右侧竖屏
  13. 敲开bp神经网络之门(三,机器视觉斑点blob匹配中使用)
  14. 语音外呼机器人邀请用户对营业厅评价
  15. layui数据表格的字体颜色
  16. ps 2019直装版 for Mac
  17. PowerBI:关于PBIX,PBIT及PBIDS
  18. 使用photoshop将图片制作成圆形
  19. 解决centos 个别命令command not found 每次打开虚拟机都要sourc .bashrc
  20. Python爬取微博热搜榜,将数据存入数据库

热门文章

  1. Django学习之视图层
  2. Druid——Hadoop-based Batch Ingestion
  3. Java字符串(超超超详细)
  4. 李帅燕山大学计算机,燕山大学第二十三届学生会复试结果
  5. oracle教程课件,Oracle入门教程(PPT课件)
  6. 【IC卡】终极版复卡器操作方法 ID卡读取方法
  7. 使用jquery对接高德地图地址四级联动
  8. 关于笔记本电脑无法连接到网络
  9. 小米数据收集利器:AgentSource
  10. 【Unity3D】Unity5打不开VS2017,Unity打开VS2017异常,并且有时候最后打开的是Mono的解决方案