[toc]
0.从问题出发
1 | synchronized vs lock,既生瑜,何生亮? |
---|---|
2 | synchronized是如何实现的? |
3 | 所谓对象与monitor关联,是什么意思? |
4 | synchronized对象时,对象头会有变化。ReentrantLock加锁后,对象头本身变化吗? |
5 | object的wait()/notify()方法有什么用? |
6 | hotspot内部是如何实现的? |
1.概述
本文意在探讨java两大类同步机制synchronized
与锁(基于AbstractQueuedSynchronizer如ReentrantLock
)的异同,及其背后的实现原理。首先给出一些结论,后续验证和分析:
- 前者内置于java语言本身,是语法糖,重在开发便捷性和效率;后者由jdk实现,重在灵活性和性能
synchronized
基于monitor
概念设计,在jvm内部实现ReentrantLock
等锁基于AQS(AbstractQueuedSynchronizer)
,在jdk中实现- 偏向/轻量/重量锁等概念是jdk1.6针对
synchronized
的性能优化,与其它锁机制无关,对其它锁而言,对象头不会变化 synchronized
通过Object的wait/notify方法提供隐性条件协作
2.基础概念
2.1 java对象头
任意java对象都包含对象头,以保存相关描述信息
对象头 | Mark word |
---|---|
2.2 monitor
monitor是由C.A.R. Hoare等人提出的一种线程同步机制,提供:
- 互斥功能
- 线程间协作
3.对象头在加锁时的变化
3.1 synchronized(偏向/轻量/重量锁)
上述三种锁是jdk1.6为了提升synchronized性能,针对不同场景进行的三种内部优化,这三种实现会修改markword:tag字段。通过jol包打印header取值情况:
1
2
3
4
5
6
7
8
Thread.sleep(5000);
Object o = new Object();
System.out.println("未进入同步块,MarkWord 为:");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o){
System.out.println(("进入同步块,MarkWord 为:"));
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
object header同步前后变化 |
---|
至于上述三种内部锁适用于何种场景及其流转,不是本文重点,详见难搞的偏向锁终于被 Java 移除了
3.2 Lock加锁时锁对象头会变化吗?
1
2
3
4
5
6
7
8
9
10
11
12
13
ReentrantLock rl = new ReentrantLock();
System.out.println("new ReentrantLock: ");
System.out.println(ClassLayout.parseInstance(rl).toPrintable());
rl.lock();
System.out.println(" after locking: ");
System.out.println(ClassLayout.parseInstance(rl).toPrintable());
try {
System.out.println(" critical running:");
} finally {
rl.unlock();
System.out.println(" release locking: ");
System.out.println(ClassLayout.parseInstance(rl).toPrintable());
}
加锁前后object header无变化 |
---|
4.synchronized的实现
上述代码编译后字节码:
synchronized 在编译后, 在jvm内部由指令monitorenter/monitorexit 实现 |
|
---|---|
the java virtual machine specification 8中的定义 |
根据描述,当锁对象关联的monitor的entry count:
- 为0 时,取得锁,成为持有者
- 不为0当已经持有时,则增1,重入持有
- 不为0且被其它线程持有,则阻塞
5.所谓每个Object关联一个monitor意味着什么?
根据Monitors and Exceptions : How to Implement Java efficiently: Andreas Krall and Mark Probst
sun的实现是使用锁对象的object identifier在hashmap中关联monitor对象(首次加锁时生成)。当然,实际上各个版本的jvm到底如何实现,还需要具体研究jvm源码,本文暂时止步于此34。有个monitor参考实现5
6.synchronized时的线程间协作
通过Object对象中的wait()/notify()
方法,二者包含且仅包含了一个隐性Condition变量
7.synchronized锁模型示意
synchronized实现逻辑模型 |
---|