2014-12-27 64 views
4

你會看到下面的代碼試圖實現以下目標:如何使兩個線程輪流修改數組列表?

  • 加「0線」到ArrayList中
  • 打印ArrayList中,即「行0」
  • 刪除最後一個項目的最後一個項目從ArrayList中

  • 加「1號線」到ArrayList中

  • 打印ArrayList中,即「1號線」的最後一個項目 從刪除最後一個項目arraylist

...等等沒有結束。

所以,我希望輸出很簡單:

線0

線1

..

..

不過,我得到的是一個隨機量「線我」的地方,我也是隨機的。 下面是一個示例輸出:

線0

線38919

線47726

線54271

然後程序卡在這似乎是即使那並不是一個僵局沒有意義,因爲變量'持有'只能是真或假,並且這些情況中的任何一種都應該允許其中一個線程工作。

import java.util.*; 

public class Test { 

    static boolean held = true; 
    static ArrayList<String> line = new ArrayList<>(); 


    public static void main(String[] args) { 

     new Thread() { 
      @Override 
      public void run() { 
       int i = 0; 
       while(true) { 
        if(held) { 
         line.add("Line " + i); 
         i++; 
         held = false; 
        } 
       } 
      } 


     }.start(); 

     while(true) { 
      if(!held) { 
       System.out.println(line.get(line.size() - 1)); 
       line.remove(line.size() - 1); 
       held = true; 

      }else continue; 
     } 

    } 


} 
+2

我在ideone上運行了這個,輸出結果和你期望的一樣。所以這一定是一些與平臺有關的問題。嘗試將「volatile」添加到所保存的變量中。 – 2014-12-27 21:04:32

+0

你可以嘗試使用'信號量' – fge 2014-12-27 21:05:07

+1

@ Martijn Courteaux使'持有'揮發做了伎倆,謝謝! – Dziugas 2014-12-27 21:12:53

回答

6

可能的事實是,您的held變量不是volatile正在導致死鎖。計算機上的不同核心將擁有自己的內存緩存,這些緩存並不一定會同時更新。爲確保所有線程都可以看到更改,您應該使其變得不穩定。你也可以使用AtomicBoolean,或者同步對代碼塊的訪問。

0

你可以使用這兩個線程同步上的鎖定對象,然後讓每個線程做他們的名單上的動作,然後使用等待和通知交替喚醒其他線程也將做同樣的事情。

0

我認爲這種情況下,最好使用同步列表代替的ArrayList:

List line = Collections.synchronizedList(new ArrayList(...)); 
1

的第一件事情是,在你的主要創建兩個不同的線程的第一個線程(在孩子)以及將要處理主要while循環的主要線程。這意味着您正在同時運行它們,因此您無法確定當每個線程正在使用它時,持有的值是。要解決這個問題,你必須使用信號量或互斥量來訪問持有進行更改。

第二件事是在你的while循環中沒有任何東西使得程序離開它們,這就是爲什麼它可能導致你無限循環。