2013-05-06 114 views
0

我有一個關於wait()和notifyAll()方法的小問題。 代碼模擬兩個線程的'Race'。調用notifyAll的好方法是什麼?

讓我們看看代碼 - 問題在於notifyAll()方法對於等待線程不起任何作用,導致主要方法首先得到鎖定...簡單的解決方法是設置一些延遲(參見注釋行) 。但這是一個不好的做法。這個問題有什麼好的解決方法?我只想使用wait/notifyAll/join方法。

public class TestThreads { 
    public static void main(String[] args) throws InterruptedException { 
    System.out.println("_start main"); 
    Object lock = new Object(); 
    Thread t1 = new Thread(new Car("Red car", lock)); 
    Thread t2 = new Thread(new Car("Black car", lock)); 
    t1.start(); 
    t2.start(); 
    //Thread.sleep(10L); 
    synchronized (lock){ 
     System.out.println("Let`s go!"); 
     lock.notifyAll(); 
    } 
    t1.join(); 
    t2.join(); 
    System.out.println("_exiting from main..."); 
    } 
} 

class Car implements Runnable { 
    private final String name; 
    private final Object lock; 

    public Car(String name, Object lock) { 
    this.name = name; 
    this.lock = lock; 
    } 

    @Override 
    public void run() { 
    int distance = 100; 
    synchronized (lock){ 
     try{ 
     System.out.println(name + " waiting..."); 
     lock.wait(); 
     }catch (InterruptedException e){ 
     e.printStackTrace(); 
     } 
    } 
    System.out.println(name + " started..."); 
    while (distance != 0){ 
     try{ 
     Thread.sleep((long) (100 * Math.random())); 
     }catch (InterruptedException e){ 
     e.printStackTrace(); 
     break; 
     } 
     distance--; 
     if (distance % 20 == 0 && distance != 0){ 
     System.out.println(name + " " + distance+ " miles left"); 
     } 

     else if (distance == 0){ 
     System.out.println(name + " finished race!!!"); 
     } 
    } 
    System.out.println("_exiting from thread of " + name + " move simulation..."); 
    } 
} 

PS。對不起,我的英語不好。

謝謝你的答案。 那麼,這個解決方案更好嗎?

public class TestThreads { 
    public static void main(String[] args) throws InterruptedException { 
    System.out.println("_start main"); 
    LightSignal lock = new LightSignal(); 
    Thread t1 = new Thread(new Car("Red car", lock)); 
    Thread t2 = new Thread(new Car("Black car", lock)); 
    t1.start(); 
    t2.start(); 
    synchronized (lock){ 
     Thread.sleep(1000L); 
     lock.isGreen = true; 
     System.out.println("Let`s go!"); 
     lock.notifyAll(); 
    } 
    t1.join(); 
    t2.join(); 
    System.out.println("_exiting from main..."); 
    } 
} 

class Car implements Runnable { 
    private final String name; 
    private final LightSignal lock; 

    public Car(String name, LightSignal lock) { 
    this.name = name; 
    this.lock = lock; 
    } 

    @Override 
    public void run() { 
    int distance = 100; 
    synchronized (lock){ 
     try{ 
     while (!lock.isGreen){ 
      System.out.println(name + " waiting..."); 
      lock.wait(); 
     } 
     }catch (InterruptedException e){ 
     e.printStackTrace(); 
     } 
    } 
    System.out.println(name + " started..."); 
    while (distance != 0){ 
     try{ 
     Thread.sleep((long) (100 * Math.random())); 
     }catch (InterruptedException e){ 
     e.printStackTrace(); 
     break; 
     } 
     distance--; 
     if (distance % 20 == 0 && distance != 0){ 
     System.out.println(name + " " + distance + " miles left"); 
     } 
    } 
    System.out.println(name + " finished race!!!"); 
    System.out.println("_exiting from thread of " + name + " move simulation..."); 
    } 
} 

class LightSignal { 
    public boolean isGreen = false; 
} 
+1

您的決定使用等待/通知是一個糟糕的。你需要圍繞這些原始圖元進行更多的編程才能獲得可靠的行爲。對於初學者,你必須*等待條件*,而不是原始的'notifyAll'信號。這在整個網絡中都有記錄,例如[here](http://stackoverflow.com/questions/1038007/why-should-wait-always-be-called-inside-a-loop)。 – 2013-05-06 14:07:59

回答

1

當你調用notifyAll的(),您需要更改的狀態,當你正在等待(),您需要檢查在一個循環的狀態。如果你不這樣做

  • notifyAll()只通知正在等待()的線程,而不是線程開始等待稍後。
  • wait()可以虛假地喚醒。

在這種情況下,最簡單的解決方案就是不用擔心。您正在等待100毫秒的隨機延遲,因此嘗試同步這種隨機系統的開始並不會產生很大的影響。

當循環結束時,我會認爲「比賽已完成」,因此您不需要if子句。

相關問題