今天一位同學問我題目中的這個問題,并給了我下面的代碼,花了好久才看懂,這里總結一下.
實現(xiàn)代碼如下所示:
package com.multithread.wait;
public class MyThreadPrinter2 implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThreadPrinter2(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);
MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);
new Thread(pa).start();
Thread.sleep(100); //確保按順序A、B、C執(zhí)行
new Thread(pb).start();
Thread.sleep(100);
new Thread(pc).start();
Thread.sleep(100);
}
}
首先,我們提出一個概念模型,就是Java對象中,包含了這么兩部分內容:
ArrayList<Thread> threadsWhoWaitForThisObject
Thread threadWhoEnterTheMonitor
在執(zhí)行synchronized塊時,線程會比較相應對象的threadWhoEnterTheMonitor是否是null或者當前線程,如果是的話,就將相應對象的threadWhoEnterTheMonitor設置為當前線程,并且執(zhí)行synchronized塊.當線程調用wait()方法時,會將線程加入到對應對象的threadsWhoWaitForThisObject,并且將對應對象的threadWhoEnterTheMonitor設置為null,讓其他的線程可以得到執(zhí)行.當線程從synchronized塊中出來時,也會將對應對象的threadsWhoEnterTheMonitor設置為null.
當然,這只是一個概念模型.Java中對象是否包含上面提到的這兩個區(qū)域,我還不清楚.
清楚了上面的概念模型后,我們照著上面的代碼走一個循環(huán)就清楚了.
首先,是線程pa執(zhí)行,其次是pb,最后是線程pc執(zhí)行.同時有三個對象,a,b,c,它們和上面的三個線程是一一對應的關系.下面我們將會從這三個執(zhí)行期間a,b,c中的threadWhoEnterTheMonitor以及threadsWhoWaitForThisObject的變化來解釋其實現(xiàn)原理.
在第一次pa執(zhí)行期間,三個對象的threadWhoEnterTheMonitor以及threadsWhoWaitForThisObject的變化如下:
c's threadWhoEnterTheMonitor: pa -> null
a's threadWhoEnterTheMonitor: pa -> null
b's threadWhoEnterTheMonitor: null
a's threadsWhoWaitForThisObject: null
b's threadsWhoWaitForThisObject: null
c's threadsWhoWaitForThisObject: pa
在第一次pb執(zhí)行期間,三個對象的threadWhoEnterTheMonitor以及threadsWhoWaitForThisObject的變化如下:
a's threadWhoEnterTheMonitor: pb -> null
b's threadWhoEnterTheMonitor: pb -> null
c's threadWhoEnterTheMonitor: null
a's threadsWhoWaitForThisObject: pb
b's threadsWhoWaitForThisObject: null
c's threadsWhoWaitForThisObject: pa
在第一次pc執(zhí)行期間,三個對象的threadWhoEnterTheMonitor以及threadsWhoWaitForThisObject的變化如下:
a's threadWhoEnterTheMonitor: null
b's threadWhoEnterTheMonitor: pc -> null
c's threadWhoEnterTheMonitor: pc -> null
a's threadsWhoWaitForThisObject: pb
b's threadsWhoWaitForThisObject: pc
c's threadsWhoWaitForThisObject: pa -> null
在第一次執(zhí)行pa和pb的期間,由于prev對象對應的threadsWhoWaitForThisObject是null,所以實際上self.notify()是不會起作用的.
而在第一次執(zhí)行pc的期間,c's threadsWhoWaitForThisObject開始是pa,所以是會喚醒pa的.等到pc的synchronized執(zhí)行完后,此時盡管三個對象的threadWhoEnterTheMonitor都是null,但是此時pb和pc都沒有被喚醒,所以不存在競爭的問題.
后面的迭代就跟第一次基本上差不多了,各位可以自行嘗試走一遍.