2013-08-01 105 views
1

我有一個長度爲100的數組。我需要在多線程環境中使用它。總共有10個線程訪問數組。有可能兩個線程一次要寫入相同的索引。Array在多線程環境中。讀取和寫入兩者

Object[] data = new Object[100]; 

什麼是最好的方法來實現這一點。

解決方案1: 只有一個線程可以寫入數組。即使t1t2線程想要寫入不同的索引,必須等待。即使我們可以使用arrayList並且可以使用Collections.synchronizedList(....)。

public class ThreadSafeArray(){ 
    private Object[] data = new Object[100]; 

    public synchronized Object getValueAtIndex(int index){ 
     return data[index]; // Removing index range check for simple explanation 
    } 

    public synchronized void setValueAtIndex(int index , Object value){ 
     data[index] = value; // Removing index range check for simple explanation 

    } 
    } 

解決方案2: 兩個不同的線程可以同時在兩個不同的索引編寫。

 public class ThreadSafeArray(){ 
    private Object[] data = new Object[100]; 
    private Object[] lock = new Object[100]; 

    public Object getValueAtIndex(int index){ 
     synchronized(lock[index]) 
     { 
      return data[index]; // Removing index range check for simple explanation 
     } 
    } 

    public void setValueAtIndex(int index , Object value){ 
     synchronized(lock[index]) 
     { 
      data[index] = value; // Removing index range check for simple explanation 
     } 
    } 
    } 

有沒有更好的方法來實現這個要求?

+0

你是用'VECTOR'或'CopyOnWriteArrayList'在JAVA –

+1

你在做這個作爲一個練習,否則你最好重新發明輪子。此問題更適合codereview.stackexchange.com –

+0

@NarendraPathai練習 – HakunaMatata

回答

1

如果你有很多線程試圖寫入很多單元,那麼第二種解決方案會更好,然後第一種方法可能會創建第二種解決方案的瓶頸。

在10個線程和100個細胞的特定情況下

出現在現代計算機

0

在java中沒有大的區別,這取決於你打算如何使用您的陣列,可以把你的價值觀在AbstractQueue的ArrayList來代替。這是一個有用的一個java.util.concurrent.ConcurrentLinkedQueue

或任何類似的隊列,如

  • 的ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingDeque
  • 的SynchronousQueue
+0

我們需要索引庫訪問。順序沒有必要 – HakunaMatata

+0

@ManishBhunwal順序只是一個獎勵,你仍然可以使用隊列。將它與Executor服務相結合可以使它更有成效。查看http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html – Lai

0

我會選擇解決方案1:

我認爲它完全符合您的需求。

我認爲性能問題可以忽略。

synchronize 

您的訪問完成了這項工作。爲什麼讓它比現在更困難。

提示:wouldn't使用數組。我最好使用Collection。有一個集合 爲您的需要的每個人。

+0

第一個解決方案與順序一樣好。這比第二個好嗎? –

+0

我認爲其他線程必須等待的時間可以忽略。 – Holger

+0

任何理由忽略其他線程被阻止的持續時間? – HakunaMatata

0

它取決於線程是僅寫入值還是讀取值(例如,將值遞增1)。如果他們讀取,然後在覆蓋所有值的區域同步 - 讀取和寫入。如果從不同的單元讀取,則讀取第一個變量。如果只從相同的賣出,那麼第二種變體。如果沒有讀取任何值,則根本不需要同步。

1

首先讓我們討論如果我們在多個線程之間共享任何數據(無論是Java/C#),那麼我們需要查看哪些問題。 我們需要解決三個問題。

1. **Atomicity** of read/write operation on that datastructure 
2. **Visibility** changes by one thread are visible to other thread. 
3. **Reordering** - compiler n processor are free to reorder these instruction 
    as long as it maintains program order for single thread execution. 

現在爲您的問題,我看到的是。 你有一個固定大小的數組,你在多個線程中共享,你只是設置和獲取值。

首先參考作業是原子 因此,您的下面的方法是原子的。我不會說它是線程安全的。因爲它仍然缺乏知名度高的公司。

public void setValueAtIndex(int index , Object value){ 
     data[index] = value; // Removing index range check for simple explanation 
    } 

現在能見度保證我們可以改變我們的方法(如果你閱讀的數量超過您寫)

首先讓我們宣佈你的陣列揮發性

volatile Object [] data = new Object[100]; 

現在你的get方法會做得很好無同步關鍵字

public Object getValueAtIndex(int index){ 
     return data[index]; // Removing index range check for simple explanation 
} 

上述方法將線程安全Ë 現在一套方法,你可能需要複製陣列更改值,然後再重新分配其數據,即

public void setValueAtIndex(int index , Object value){ 
     Object tempdata = copy(data); // make a copy of that array 
     //change in the copied array 
     tempdata[index] = value; 
// reassign the array back to original array 
data = tempData; 
} 

通過上述方法,你會增加你的閱讀寫作陣列的成本的陣列性能。 你不需要同步,如果你有其他方式固定長度的數組,你需要鎖定的變異操作

+0

所有讀取都是不穩定的,請參閱數據聲明爲volatile並且在任何突變上覆制的數組再次分配給數據(即volatile)寫入。這將照顧可見性問題。 – veritas

+0

當一個數組被聲明爲volatile時,所有通過它讀取的數據都是volatile volatile – veritas

+0

對,我誤讀你的set方法。 –