2012-03-22 185 views
-1

我有兩個非常相似的程序,每個都試圖運行兩個線程OddThread和EvenThread,並嘗試按順序打印奇數和偶數。第一個工作,第二個工作。任何人都可以在第二個程序中找出錯誤嗎?Java - 多線程和同步

第一種其中工程:

public class ThreadTest { 

public static void main(String[] args) { 
    System.out.println("Odd Even test"); 
    NumHolder objNumHolder = new NumHolder(); 
    Odd o1 = new Odd(objNumHolder, "Odd Number Thread"); 
    Even e1 = new Even(objNumHolder, "Even Number Thread"); 
    o1.start(); 
    e1.start(); 
} 
} 

class NumHolder { 
private int intCurrNum; 
private boolean isEven = false; 

public synchronized void printOddNumber(String tname) { 
    while (isEven == true){ 
     try { 
      wait(); 
     }catch (InterruptedException e) { 
     } 
    } 
    isEven = true; 
    System.out.println("Thread Name="+tname + "===Number="+intCurrNum); 
    intCurrNum += 1; 
    notifyAll(); 
} 

public synchronized void printEvenNumber(String tname) { 
    while (isEven == false) { 
     try { 
      wait(); 
     } catch (InterruptedException e) { 
     } 
    } 
    isEven = false; 
    System.out.println("Thread Name="+tname + "===Number="+intCurrNum); 
    intCurrNum += 1; 
    notifyAll(); 
} 
} 

class Even extends Thread { 
private NumHolder objNumHolder; 

public Even(NumHolder p_objNumHolder, String name) { 
    super(name); 
    objNumHolder=p_objNumHolder; 
} 

public void run() { 
    for (int i = 0; i < 10; i++) { 
     objNumHolder.printEvenNumber(getName()); 
    } 
} 
} 
class Odd extends Thread { 
private NumHolder objNumHolder; 

public Odd(NumHolder p_objNumHolder,String name) { 
    super(name); 
    objNumHolder = p_objNumHolder; 
} 

public void run() { 
    for (int i = 0; i < 10; i++) { 
     objNumHolder.printOddNumber(getName()); 
    } 
} 
} 

第二代碼掛起:

class PrintClass { 
int intCurrNum; 
private boolean isEven = false; 

synchronized void printOdd(){ 
    while(isEven){ 
     try{ 
      wait(); 
     }catch(InterruptedException ie){ 
      System.out.println("Interrupted exception in printOdd()"); 
      ie.printStackTrace(); 
     } 
     isEven = true; 
     System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum); 
     intCurrNum += 1; 
     notifyAll(); 
    } 
} 

synchronized void printEven(){ 
    while(!isEven){ 
     try{ 
      wait(); 
     }catch(InterruptedException ie){ 
      System.out.println("Interrupted exception in printEven()"); 
      ie.printStackTrace(); 
     } 
     isEven = false; 
     System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum); 
     intCurrNum += 1; 
     notifyAll(); 
    } 
} 
} 
class ThreadOdd extends Thread { 
PrintClass pc = null; 

ThreadOdd(PrintClass pc , String name){ 
    super(name); 
    this.pc = pc; 
} 

public void run(){ 
    for (int i = 0; i < 10; i++) { 
     pc.printOdd(); 
    } 
} 
} 
class ThreadEven extends Thread { 
PrintClass pc = null; 

ThreadEven(PrintClass pc,String name){ 
    super(name); 
    this.pc = pc; 
} 

public void run(){ 
    for (int i = 0; i < 10; i++) { 
     pc.printEven(); 
    } 
} 
} 
public class EvenOddPrintClass { 
public static void main(String[] args){ 
    PrintClass pc = new PrintClass(); 
    Thread to = new ThreadOdd(pc,"ThreadOdd"); 
    Thread te = new ThreadEven(pc,"ThreadEven"); 
    to.start(); 
    te.start(); 
} 
} 

感謝。

+0

這個作業是否相關?如果一個線程「掛起」,這可能是因爲你的第一個線程已經鎖定了第二個線程試圖獲取鎖的資源;或者,它可能正在等待信號,但線程從未給出信號。我們需要知道'wait'函數裏面有什麼,否則很難說清楚。 – Kiril 2012-03-22 18:57:37

+0

@Lirik:這是java.lang.Object的等待方法。另一個線程繼續等待另一個線程使用printOdd/printEven方法結束時的notifyAll -calls來喚醒它,但可能它們會卡在方法同步或其他線程從while -loop和其他卡住wait():用於通知。 – esaj 2012-03-22 19:00:46

+0

@esaj ...哦,明白了。我忘了那個! – Kiril 2012-03-22 19:03:27

回答

0

我建議你在調試器中運行你的代碼,並通過這兩個線程。這非常有教育意義。你會看到錯誤的確切位置。

0

有趣。所以最初的isEven = false。如果printOdd()被首先調用,則while (isEven)測試爲false,因此printOdd()將立即退出而不生成任何輸出。您的第一個程序中的while循環僅包含wait測試,而不是整個方法。

然後,當其他線程調用printEven()時,它將調用wait()並掛起,因爲沒有其他線程可以調用notifyAll()

您只需要while環繞wait環路,因爲無論如何您打印出偶數或奇數後即將退出,對吧?所以第一個程序中的邏輯是正確的。

0

在這兩個版本中,isEven都是假的。

在第一個版本,printOddNumber將跳過整個while循環,打印奇數,設置ISEVEN爲真,並通知even線程,這將打印偶數和順序再次等通知odd線程。

在第二個版本中,printOddNumber將跳過整個while循環,包括打印數字和通知even線程。經過10次嘗試後,它將在沒有印刷任何東西的情況下退出,並且在沒有通知它的情況下將線掛起。

0
public class CountDownApp 
{ 
public static void main(String[] args) 
{ 
Thread count1 = new CountDownEven(); 
Thread count2 = new CountDownOdd(); 
count1.start(); 
count2.start(); 

} 
} 

class CountDownEven extends Thread 
{ 
public void run() 
{ 
for(int i=10;i>0;i-=2) 
{ 
System.out.print(+i+"-"); 

try { 
    Thread.sleep(2); 
} catch (InterruptedException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 
} 
} 

} 

class CountDownOdd extends Thread 
{ 
public void run() 
{ 
for(int i=9;i>0;i-=2) 
{ 
System.out.print(+i+"-"); 

try { 
     Thread.sleep(2); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 
} 

} 
+0

對不起,我不想使用sleep()來達到此目的。 – NINCOMPOOP 2012-04-01 08:53:43