操做系统在面对线程间同步的时候,会支持例如semaphore信号量和mutex互斥量等同步原语,而monitor是在编程语言中被实现的,下面介绍一下java中monitor(监视器/管程:管理共享变量以及对其的操做过程,让他们支持并发)的实现原理:java
以一个阻塞队列的实现来举例:编程
同时,java内置的synchronized关键字能够认为是MESA模型的简化版,其只能有一个条件变量,但编译器会自动添加加锁与解锁的代码。synchronized关键字能够修饰实例方法、类方法以及代码块,若是修饰的是代码块,须要制定关联的Object;若是修饰的是实例方法,那么其关联的对象其实是this;若是修饰的是类方法,那么其关联的对象是this.class。这些关联的对象就是MESA模型里的条件变量。数组
JVM基于进入和退出monitor对象来实现同步,同步代码块采用添加moniterenter、moniterexit,同步方法使用ACC_SYNCHRONIZED标记符隐式实现。每一个对象都有一个monitor与之关联,运行到moniterenter时尝试获取对应monitor的全部权,获取成功就将monitor的进入数加1(因此是可重入锁,也被称为重量级锁),不然就阻塞,拥有monitor的线程运行到moniterexit时进入数减1,为0时释放monitor。
java中每一个对象都有一个对象头,synchronized所用的锁就是存在对象头里的。若是是非数组的对象是8个字节(32位JVM)或者16字节(64位JVM),数组对象还会有一个数组长度(4个字节)。以32位JVM非数组对象为例:缓存
锁信息就存在前4个字节的MarkWord中,JVM对synchronized的加锁过程优化为:多线程
重量级锁是悲观锁的一种,自旋锁、轻量级锁与偏向锁属于乐观锁。
CAS设计读取-比较-写入三个操做,是在CPU指令层面保证其原子性,volatile是保证多线程下的内存可见性,两者需配合使用。另外还需注意CPU缓存行(一次以32/64字节为单位从主内存中读取数据到缓存)包含多个变量所带来的隐形同步问题:其中一个变量被volatile修饰,致使另一个变量在另外一个CPU核上(另外一个线程)的读写也要被强制刷新缓存。并发
管程:并发编程的万能钥匙
java 中的锁 -- 偏向锁、轻量级锁、自旋锁、重量级锁