package cn.shenzhen.feixun; public class PrintABC extends Thread{ private String name; private Object prev; private Object self; public PrintABC(String name,Object prev,Object self){ this.name=name; this.prev=prev; this.self=self; } /** * ,為了控制執行的順序,必須要先持有prev鎖, * 也就是前一個線程要釋放自身對象鎖,再去申請自身對象鎖,兩者兼備時打印字母, * 之后首先調用self.notify()釋放自身對象鎖,喚醒下一個等待線程, * 再調用prev.wait()釋放prev對象鎖,終止當前線程,等待循環結束后再次被喚醒。 * 程序運行的主要過程就是A線程最先運行,持有C,A對象鎖,后釋放A,C鎖,喚醒B。 * 線程B等待A鎖,再申請B鎖,后打印B,再釋放B,A鎖,喚醒C,線程C等待B鎖,再申請C鎖, * 后打印C,再釋放C,B鎖,喚醒A…… */ public void run(){ int count=0; while(count<10){ // 先獲取 prev鎖 如此問題中先將對象C鎖住 synchronized (prev) { //然后獲取自身的鎖如此問題中將對象A鎖住 synchronized (self) { System.out.print(name+""); count++; self.notify();//此問題中一共有三個對象ABC此時將self喚醒,是其他線程來競爭self } try { prev.wait(); /** * 注意的是notify()調用后,並不是馬上就釋放對象鎖, * 而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖, * JVM會在wait()對象鎖的線程中隨機選取一線程,賦予其對象鎖,喚醒線程,繼續執行。 */ } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { Object a=new Object(); Object b=new Object(); Object c=new Object(); PrintABC printA=new PrintABC("A", c, a);//第一個線程先將AC對象鎖住,A執行完了之后釋放鎖 PrintABC printB=new PrintABC("B", a, b); PrintABC printC=new PrintABC("C", b, c); /** * 為了避免JVM啟動ThreadA、ThreadB、ThreadC三個線程順序的不確定性。 * 需要讓A,B,C三個線程以確定的順序啟動,中間加一段sleep確保前一個線程已啟動。 */ printA.start(); /** * sleep()方法導致了當前線程暫停執行指定的時間, * 讓出cpu該其他線程,但是他的監控狀態依然保持者, * 當指定的時間到了又會自動恢復運行狀態。 */ printA.sleep(10); printB.start(); printB.sleep(10); printC.start(); printC.sleep(10); } }