sychronized是jvm中对线程同步的主要方法和机制。
Thread.sleep是让线程丢掉cpu分配资源(让调度器在某时间内不再调度该线程)。
一个对象的锁只能同时被一个线程所持有。
对于每一个线程都是两个ObjectMinor list,一个是freelist,一个是usedlist;usedlist是该线程占有那些对象的锁,一个线程可以占有多个对象的锁。
jvm ObjectMinor源代码:
ObjectMonitor() {
_header = NULL;//markOop对象头
_count = 0;
_waiters = 0,//等待线程数
_recursions = 0;//重入次数
_object = NULL;//监视器锁寄生的对象。锁不是平白出现的,而是寄托存储于对象中。
_owner = NULL;//指向获得ObjectMonitor对象的线程或基础锁
_WaitSet = NULL;//处于wait状态的线程,会被加入到wait set;
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ;//处于等待锁block状态的线程,会被加入到entry set;
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;// _owner is (Thread *) vs SP/BasicLock
_previous_owner_tid = 0;// 监视器前一个拥有者线程的ID
}
object notify() 随意获取(之前调用wait而阻塞的线程)一个线程唤醒去执行,但是去执行不一定是直接获取这个对象的锁,或者执行这个对象中方法,只是唤醒而已。但是注意:去执行object.notify的线程必须是获取该对象object的锁的线程,否则会爆出IllegalMonitorStateException。因为只有持有该对象的锁,该线程中的minor usedlist才有该对象的objectminor,才有能力获取该objectminor中的_WaitSet 等待队列。
对于ObjectMinor中EntrySet存放的阻塞block队列,我们是没有办法直接唤醒的.
每个object都包含markOop。如下图所示:
class oopDesc {
friend class VMStructs;
private:
volatile markOop _mark;//markOop:Mark Word标记字段
union _metadata {
Klass* _klass;//对象类型元数据的指针
narrowKlass _compressed_klass;
} _metadata;
// Fast access to barrier set. Must be initialized.
static BarrierSet* _bs;
public:
markOop mark() const { return _mark; }
markOop* mark_addr() const { return (markOop*) &_mark; }
void set_mark(volatile markOop m) { _mark = m; }
void release_set_mark(markOop m);
markOop cas_set_mark(markOop new_mark, markOop old_mark);
// Used only to re-initialize the mark word (e.g., of promoted
// objects during a GC) -- requires a valid klass pointer
void init_mark();
Klass* klass() const;
Klass* klass_or_null() const volatile;
Klass** klass_addr();
narrowKlass* compressed_klass_addr();
}
oopDesc
--继承-->
markOopDesc
--方法monitor()-->
ObjectMonitor-->enter、exit 获取、释放锁
markOopDesc类
openjdk\hotspot\src\share\vm\oops\markOop.hpp下markOopDesc继承自oopDesc,并拓展了自己的方法monitor(),如下图
ObjectMonitor* monitor() const {
assert(has_monitor(), "check");
// Use xor instead of &~ to provide one extra tag-bit check.
return (ObjectMonitor*) (value() ^ monitor_value);
}
说说EntrySet和waitSet队列:
(1)所有期待获得锁的线程,在锁已经被其它线程拥有的时候,这些期待获得锁的线程就进入了Object Lock的entry set区域。
(2)所有曾经获得过锁,但是由于其它必要条件不满足而需要wait的时候,线程就进入了Object Lock的wait set区域 。
(3)在wait set区域的线程获得Notify/notifyAll通知的时候,随机的一个Thread(Notify)或者是全部的Thread(NotifyALL)从Object Lock的wait set区域进入了entry set中。
(4)在当前拥有锁的线程释放掉锁的时候,处于该Object Lock的entryset区域的线程都会抢占该锁,但是只能有任意的一个Thread能取得该锁,而其他线程依然在entry set中等待下次来抢占到锁之后再执行。
当获取当前锁的线程离开同步区,对象的锁值减一,且锁值为0(锁可以重复进入,每次进入自加1),那么监视器会释放信息量,Entry_set队列中的线程会抢锁,只有一个线程可以获取锁。