Synconized,对象,锁,锁升级
锁
-
对于普通同步方法,锁是当前实例对象
-
对于静态同步方法,锁是当前class类对象
-
对于同步方法块,锁是括号内对象。
JVM基于进入和退出Monitor对象来实现方法和代码块同步。每个java对象都有一个Monitor与之对应。代码块同步是用monitorenter和monitorexit关键字实现。monitor的本质是依赖于底层操作系统的Mutex Lock实现。
synchronized用的锁是在Java对象头里的。如果对象是数组类型,则虚拟机用3个字宽存储对象头。如果对象是非数组类型,则用2个字宽存储对象头。在32位虚拟机中,1字宽=4字节(32bit)
对象头信息
长度 | 内容 | 说明 |
32/64bit |
Mark word |
存储对象的HashCode或锁信息 |
同上 |
Class Metadata Adress |
存储到对象类型数据的指针 |
32bit |
Array length |
数组长度(如果对象是数组) |
mark word在运行期间会随着锁标志位变化而变化。(锁升级)
锁升级
JSE1.6做的优化
1.6中锁一共有4种状态:
-
无锁
-
偏向锁(自旋)
-
轻量级锁(自旋)
-
重量级锁
无锁
无竞争就无锁
偏向锁(可重入锁)
偏向锁的markWord记录的是持有锁的线程id
出现竞争的时候用CAS来获取锁。出现竞争就做偏向锁撤销逻辑,如果做撤销操作时,有线程持有偏向锁,则偏向锁升级为轻量级锁,将Mark word信息修改为轻量级锁,并copy到原偏向锁线程中。
轻量级锁
CAS操作将对象头的Mark word中锁记录指针指向当前线程锁记录。说明哪个线程持有锁。
CAS操作失败达到一定次数之后(10?),升级为重量锁,等待唤醒。
重量级锁
mark word指向Monitor对象的指针,互斥锁,阻塞没有竞争到锁的线程