所有对象都自动含有单一的锁与一个对象可以被多次加锁的矛盾?
关注者
87被浏览
7,317登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏
Java对象可以被当作锁(monitor)来使用,用于synchronized块或者synchronized修饰的方法。
Monitor并不是一个暴露给用户可见的Java对象。它是JVM的内部实现细节,对上层应用来说只能通过monitorenter / monitorexit字节码(用于实现Java语言的synchronized块)或由ACC_SYNCHRONIZED修饰的方法(用于实现Java语言中被synchronized关键字修饰的方法)所使用。
一个完整的monitor结构,语义上说大致会有这样的一些东西:
struct monitor_t {
Object* object;
Thread* owner;
int recursion_count;
Thread** wait_list;
// ...
};
当一个Java对象被当作monitor使用时,它会有足够的内部数据结构(例如说在对象头里的隐藏字段)去找到它对应的monitor结构(例如上面示意用的monitor_t),而monitor自身通常会记录:
- object:该monitor对应的Java对象是谁
- owner:该monitor当前被哪个Java线程所持有
- recursion_count:持有该monitor的线程递归锁了该monitor多少次
- wait_list:还有哪些线程在等该monitor
- … 其它一些每个JVM实现不同的具体信息,例如说具体平台上的mutex / semaphore等。
在这样的monitor_t结构上加锁(monitorenter)的时候一条快速路径就是递归加锁:(下面简易伪代码)
void monitor_enter(Object* obj, Thread* thread) {
monitor_t* mon = obj->monitor();
if (mon == nullptr) { // not locked yet
monitor_t* new_mon = get_free_monitor(obj, thread);
if (!install_monitor(obj, new_mon)) {
// lost the race of installing the monitor onto the object header,
// some other thread got to create and own the monitor first
obj->monitor()->wait(thread);
}
mon = obj->monitor();
}
if (mon->owner() == thr) { // recursive locking
mon->inc_recursion_count();
return;
}
// non-recursive locking
// ...
}
当然,现代高性能JVM都对monitor有各种优化来降低其空间和时间开销,所以并不总是会使用类似上面的monitor_t那样完整的结构。
在HotSpot VM里,由轻到重有:偏向锁(biased lock) -> 轻量锁(thin lock) -> 重量锁(inflated lock)这几个级别的锁。其中只有重量锁状态下会有一个“ObjectMonitor”结构跟上述示意用的monitor_t结构类似,而偏向锁和轻量锁都只需要在别的地方记录少量信息即可。
关于偏向锁与轻量锁,感兴趣的同学可以参考一下这个演示稿的第25-35页:
https://www.cs.princeton.edu/picasso/mats/HotspotOverview.pdf