今天重新把昨晚的線程同步面試題做一遍時,發現實際情況運行下來時,線程一直不同步。后來經過不斷測試,發現自己的一個誤區。
之前一直以為,線程如果被喚醒后再次執行時,會從頭開始運行這個線程,也就是重新運行Runnable中的run()方法;
而實際情況是,被喚醒並且被執行的線程是從上次阻塞的位置從下開始運行,也就是從wait()方法后開始執行。
所以判斷是否進入某一線程的條件 是用while判斷,而不是用If判斷判斷。
下面舉例說明:
如果三個線程同步工作,第一個線程打印1,2,3,4,5 ,然后第二個線程打印1,2,3,4,5 ,接着第三個線程也打印 1,2,3,4,5,重復100次。
1 public class Thread_test { 2 3 static final manage m = new manage(); 4 5 public static void main(String[] args) { 6 //線程一 7 new Thread(new Runnable() { 8 @Override 9 public void run() { 10 // TODO Auto-generated method stub 11 for(int i=0;i<50;i++){ 12 m.threadPrint(i,0); 13 } 14 } 15 }).start(); 16 17 //線程二 18 new Thread(new Runnable(){ 19 20 public void run(){ 21 for(int i=0;i<50;i++){ 22 m.threadPrint(i,1); 23 } 24 } 25 }).start(); 26 27 //線程三 28 new Thread(new Runnable(){ 29 30 public void run(){ 31 for(int i=0;i<50;i++){ 32 m.threadPrint(i,2); 33 } 34 } 35 }).start(); 36 37 } 38 39 } 40 41 42 //控制線程執行的順序 43 class manage{ 44 //權限,0代表1號線程執行,1代表二號線程執行,2代表三號線程執行 45 private int isA = 0; 46 47 public synchronized void threadPrint(int i,int n){ 48 /*該處應用while來判斷是否輪到該線程執行,假如用If判斷的話,如果該線程阻塞后再次被喚醒執行時(其他線程調用this.notifyAll()),
他會從this.wait()后面的代碼開始執行,即時沒輪到該線程執行*/ 49 while(this.isA != n){ 50 try {
this.wait(); 53 } catch (Exception e) { 54 // TODO: handle exception 55 } 56 } 57 for(int j=0;j<5;j++){ 58 System.out.println(Thread.currentThread().getName()+":"+(j+1)+" loop in "+(i+1)); 59 } 60 this.isA = (this.isA+1)%3;//將權限傳遞給后一個進程62 this.notifyAll(); 63 } 64 65 66 67 }