本文代码基于jdk8 重点看代码,文字都是简介。
本文主要描述synchronized锁了对象之后,对象头发生了什么变化。
首先看看markOop.hpp 里的描述,由于本人非C++程序员,所以就不从源码上说道了。这里是描述不同位,对象的信息。亲详细看最后两位的描述。我们将会对最后两位lock信息做一个展示。
// 32 bits:
// --------
// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
// size:32 ------------------------------------------>| (CMS free block)
// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
// size:64 ----------------------------------------------------->| (CMS free block)
然后我们继续看下面一段代码注释
// - the two lock bits are used to describe three states: locked/unlocked and monitor.
//
// [ptr | 00] locked ptr points to real header on stack
// [header | 0 | 01] unlocked regular object header
// [ptr | 10] monitor inflated lock (header is wapped out)
// [ptr | 11] marked used by markSweep to mark an object
// not valid at any other time
整理出了最后被锁后,对象头最后两位的信息。
锁的状态 | 锁标志 | 代码里的解释 |
---|---|---|
轻量级锁 | 00 (0) | ptr points to real header on stack |
重量级锁 | 10 | inflated lock (header is wapped out) |
无锁 | 01 (1) | regular object header |
GC标记状态 | 11 | used by markSweep to mark an object not valid at any other time |
然后我们开始测试,可以参照上面的信息。
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
*
* @author 铁拳阿牛
* @createTime 2018/7/12 下午5:53
**/
public class TestSync {
private static Unsafe unsafe;
//为了只显示最后两位。我们不太关注对象头前面的信息。
private static final long MOD = 3L;
public static void main(String[] args) throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(Unsafe.class);
final Object o = new Object();
System.out.println(" 这里我们只取对象头信息的锁标记位!");
System.out.println("一 无锁 : " + Long.toBinaryString(MOD & unsafe.getLong(o, 0L)));
lock(o);
System.out.println("GC 标记阿牛无能未力");
}
public static void lock(final Object o) throws InterruptedException {
// 轻量锁 第一次锁
synchronized (o) {
System.out.println("二轻量锁: " + Long.toBinaryString(MOD & unsafe.getLong(o, 0L)));
// 锁膨胀
syncObject(o, 100L);
System.out.println("三重量锁: " +Long.toBinaryString(MOD & unsafe.getLong(o, 0L)));
}
}
/**
* ObjectMonitor 让锁发生膨胀
* Thread.sleep(time);一定要有这个,不然可能Main 线程先执行。不能打印出重量锁的标记
*
* @param o
* @param time
* @throws InterruptedException
*/
public static void syncObject(final Object o, long time) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
synchronized (o) {
}
}
}).start();
//让上面的线程一定先执行完
Thread.sleep(time);
}
}
我们拿到结果
这里我们只取对象头信息的锁标记位!
一 无锁 : 1
二轻量锁: 0
三重量锁: 10
GC 标记阿牛无能未力
网友评论