從一個(gè)例子開(kāi)頭:
@Slf4j
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread_new = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) {
}
log.info("Thread------>:{}", Thread.currentThread().getName());
},"thread_new");
thread_new.start();
thread_new.join();
log.info("Thread------>:{}", Thread.currentThread().getName());
log.info("end");
}
}
毫無(wú)疑問(wèn)丁稀,會(huì)打印:
Thread------>:Thread-0
Thread------>:main
end
在Thread類中:
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
在主線程中調(diào)用 thread_new.join()方法會(huì)使主線程阻塞盏檐,進(jìn)入wait()狀態(tài)蜗巧,直到thread_new線程執(zhí)行完畢睹簇,那么為什么會(huì)產(chǎn)生這樣的現(xiàn)象呢。
先從synchronized 說(shuō)起寥闪,synchronized在java中如果作為非靜態(tài)方法的描述符太惠,則等同于在方法第一行加上
synchronized(this){},這時(shí)調(diào)用 thread_new.join()疲憋,則this指向的是當(dāng)前的thread_new對(duì)象凿渊,所以當(dāng)前thread_new對(duì)象的對(duì)象頭,會(huì)指向monitor對(duì)象缚柳,monitor中指向的線程為主線程埃脏,while (isAlive()) {wait(0);},isAlive()為Thread中的方法,會(huì)先判斷thread_new線程是否存活秋忙。顯然彩掐,isAlive()為true,這時(shí)直接調(diào)用wait(0)會(huì)使當(dāng)前thread_new對(duì)象頭中指向的monit對(duì)象中灰追,記錄的線程(主線程)堵幽,進(jìn)入waitSet。使主線程進(jìn)入wait狀態(tài)弹澎。等到thread_new的線程終結(jié)朴下,在jvm中會(huì)觸發(fā)thread_new對(duì)象的thread_exit()方法,在該方法中會(huì)調(diào)用notiyAll()方法苦蒿,喚醒該對(duì)象頭中waitSet中的線程殴胧。
ObjectMonitor() {
_header = NULL;
_count = 0; //記錄個(gè)數(shù)
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL; //_owner指向持有ObjectMonitor對(duì)象的線程
_WaitSet = NULL; //處于wait狀態(tài)的線程,會(huì)被加入到_WaitSet
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; //處于等待鎖block狀態(tài)的線程刽肠,會(huì)被加入到該列表
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
}