2013-05-20 21 views
1

我有兩個線程都需要訪問一個ArrayList<short[]>實例變量。如何在訪問java ArrayList時阻止兩個線程發生衝突?

一個線程會異步通過回調添加short[]項目添加到列表時,新的數據已經到達:void dataChanged(short[] theData)

另一個線程會定期檢查列表中有項目,如果這樣做,是怎麼回事遍歷所有項目,處理它們,並將它們從數組中移除。

如何設置這個以防止兩個線程之間發生衝突?

這做作代碼示例目前拋出一個java.util.ConcurrentModificationException

//instance vairbales 
private ArrayList<short[]> list = new ArrayList<short[]>(); 

//asynchronous callback happening on the thread that adds the data to the list 
void dataChanged(short[] theData) { 
    list.add(theData); 
} 

//thread that iterates over the list and processes the current data it contains 
Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 

     while (true) { 

      for(short[] item : list) { 
       //process the data 
      } 

      //clear the list to discared of data which has been processed. 
      list.clear(); 

      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
}); 

回答

4

最簡單的方法是列出的類型更改爲thread safe list implementation

private List<short[]> list = new CopyOnWriteArrayList<short[]>(); 

注意,此類型的列表如果你經常改變它(添加/刪除)並不是非常有效 - 但是如果它適合你,這是一個簡單的解決方案。

如果您需要更多的效率,你可以使用一個synchronized list代替:

private List<short[]> list = Collections.synchronizedList(new ArrayList<short[]>()); 

但你需要爲迭代同步:

synchronized(list) { 
    for(short[] item : list) { 
     //process the data 
    } 
} 

編輯:建議使用BlockingQueue可能會更好但是需要對代碼進行更多的更改。

7

您可能希望使用producer consumer隊列(如ArrayBlockingQueue)或類似的併發集合。

生產者 - 消費者問題(也稱爲有界緩衝區問題)是一個多進程同步問題的經典示例。該問題描述了兩個進程,即生產者和消費者,他們共享一個用作隊列的公共固定大小的緩衝區。生產者的工作是生成一段數據,將其放入緩衝區並重新開始。與此同時,消費者一次只消耗一個數據(即從緩衝區中刪除數據)。問題是確保生產者不會嘗試將數據添加到緩衝區,如果它已滿,並且消費者不會嘗試從空緩衝區中刪除數據。

一個線程offer小號short[] S和其他take()Ş他們。

+0

+1這就是要走的路! – assylias

+0

+1正確的方法來設計解決方案 – Stephan

0

看看Java的同步支持。

This page涵蓋了在指定對象上同步一組語句。也就是說:只有一個線程可以同時執行在該對象上同步的任何部分,其他所有部分都必須等待。

0

您可以使用​​塊,但我認爲最好的解決方案是不要在線程之間共享可變數據。

讓每個線程在自己的空間中寫入,並在工作人員完成時收集和彙總結果。