2017-04-24 63 views
0

Main.java:具有最高優先級的Java線程沒有得到執行

public class Main { 
    public static void main(String[] args) { 
     final Semaphore semp = new Semaphore(1); 
     for (int facultyNO = 1; facultyNO <= 10; facultyNO++) { 
      final int NO = facultyNO; 
      Runnable run = new Runnable() { 
       public void run() { 
        try { 
         while (true) { 
          semp.acquire(); 
          System.out.println("No." + NO + " grab a candy"); 
          Bowl.candy--; 
          System.out.println("Candy num left:" + Bowl.candy); 
          semp.release(); 
          Thread.sleep((long) (1000)); 
         } 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      }; 
      Thread faculty = new Thread(run); 
      faculty.setPriority(Thread.MIN_PRIORITY); 
      faculty.start(); 
     } 
     Thread TA = new Thread(() -> { 
      try { 
       while (true) { 
        if (Bowl.candy < 0) { 
         semp.acquire(); 
         System.out.println("TA fills the candy bowl"); 
         Bowl.candy = 10; 
         System.out.println("Candy num left:" + Bowl.candy); 
         semp.release(); 
        } 
       } 
      }catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     }); 
     TA.setPriority(Thread.MAX_PRIORITY); 
     TA.start(); 
    } 
} 

Bowl.java:

public class Bowl { 
    static int candy = 10; 
} 

我給線程 「TA」 最高優先級,因爲我希望它只要Bowl.candy = 0就可以立即執行以填充碗。但是,控制檯打印:

No.2 grab a candy 
Candy num left:9 
No.1 grab a candy 
Candy num left:8 
No.4 grab a candy 
Candy num left:7 
No.6 grab a candy 
Candy num left:6 
No.7 grab a candy 
Candy num left:5 
No.8 grab a candy 
Candy num left:4 
No.3 grab a candy 
Candy num left:3 
No.5 grab a candy 
Candy num left:2 
No.10 grab a candy 
Candy num left:1 
No.9 grab a candy 
Candy num left:0 
No.2 grab a candy 
Candy num left:-1 
No.1 grab a candy 
Candy num left:-2 
No.4 grab a candy 
Candy num left:-3 
No.6 grab a candy 
Candy num left:-4 
No.7 grab a candy 
Candy num left:-5 
No.8 grab a candy 
Candy num left:-6 
No.3 grab a candy 
Candy num left:-7 
No.5 grab a candy 
Candy num left:-8 
No.10 grab a candy 
Candy num left:-9 
No.9 grab a candy 
Candy num left:-10 

好像if (Bowl.candy < 0)從未得到執行中的代碼。爲什麼?

+4

線程優先級不是操作系統調度程序遵循的硬規則。如果你有線程間依賴性(就像一個線程應該在其他線程之前執行)那麼基本上你不需要線程。線程專門處理計算可以獨立完成的事實。如果您正在尋找線程之間的共享狀態,則需要使用其他併發機制。這可能會幫助你更多http://stackoverflow.com/questions/8811535/inconsistent-results-with-java-threads – kosa

回答

3

你必須在這種情況下訪問變量之前獲取鎖:

semp.acquire(); 
if (Bowl.candy < 0) { 
    System.out.println("TA fills the candy bowl"); 
    Bowl.candy = 10; 
    System.out.println("Candy num left:" + Bowl.candy); 
} 
semp.release(); 

另一種選擇:

Bowl.candy都將被聲明爲volatile否則就不能保證其他線程可以看到更改這個變量。或Bowl.candy必須僅在​​塊中進行訪問。

+0

這不是信號量在做什麼? – Michael

+0

@Michael,信號量在獲取變量後保證可見性。但是你在獲得鎖之前訪問'Bowl.candy':'if(Bowl.candy <0){semp.acquire(); ...',所以它總是看到 – vhula

1

我懷疑這是一個競態條件問題。你正在檢查這個值,然後我懷疑另一個線程已經佔用了信號量,所以你不能改變它的值。

如果您更改信號量來包裝支票和作業,您的結果會稍微好一些。

Thread TA = new Thread(() -> { 
    try { 
     while (true) { 
      semp.acquire(); 
      if (candy < 0) { 
       System.out.println("TA fills the candy bowl"); 
       Bowl.candy = 10; 
       System.out.println("Candy num left:" + Bowl.candy); 
      } 
      semp.release(); 
     } 
    } 
    //... 
}); 

但是,由於時間安排問題,你會得到的結果是這樣的:

Candy num left:2 
No.2 grab a candy 
Candy num left:1 
No.3 grab a candy 
Candy num left:0 
No.5 grab a candy 
Candy num left:-1 //!!! 
No.6 grab a candy 
Candy num left:-2 //!!! 
TA fills the candy bowl 

由於Nambari指出的那樣,你可能不希望與多線程來解決這個問題。

+0

謝謝。我試過你的解決方案,它的工作!每次糖果= 0時,它都會被填滿。我不知道爲什麼會發生這種情況...... –

+0

@XINDILI:如果解決方案適合您,您需要接受答案。 – kosa

+0

@XINDILI我會帶一點鹽。多次運行它以驗證它是否符合您的期望。也許寫一個單元測試。我認爲,你所希望的最好的一點是它依賴於平臺。我已經目睹它不適合自己(低於零),所以危險肯定存在。 – Michael