数组在多线程环境中。读写两者

时间:2013-08-01 10:44:05

标签: java arrays multithreading thread-safety

我有一个长度为100的数组。我需要在Multi Threaded环境中使用它。总共有10个线程访问数组。可能有两个线程t1& t2希望一次写入相同的索引。

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
      } 
    }
  }

有没有更好的方法来实现此要求?

5 个答案:

答案 0 :(得分: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.

现在为我的问题所见。 你有一个固定大小的数组,你在多个线程之间共享,你只是设置和获取值。

首先,参考分配是原子的 所以你的下面的方法是原子的。我不会说它是线程安全的。因为它还缺乏 能见度gaurantees。

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

现在为了可见性保证我们可以改变我们的方法(如果你读取的数量超过你的写作)

首先让你的数组声明为volatile

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

现在你的get方法没有synchronized关键字

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

上述方法将是线程安全的 现在对于set方法,您可能需要复制数组更改值,然后再次重新分配数据,即

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;   
}

使用上述方法,您将提高读取数组的性能,而不是编写数组的成本。 如果您有固定长度的数组,则不需要同步,否则您需要锁定变异操作

答案 1 :(得分:0)

如果你有很多线程试图写入很多单元格,那么第二种解决方案会更好,然后第一种方法可能会在第二种解决方案中创建瓶颈。

在10个线程和100个单元格的给定情况下,现代计算机没有太大区别

答案 2 :(得分:0)

在java中,根据您打算如何使用数组,可以将您的值放在AbstractQueue ArrayList中。这是一个有用的java.util.concurrent.ConcurrentLinkedQueue

或任何类似的队列,例如

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingDeque
  • 的SynchronousQueue

答案 3 :(得分:0)

我会选择解决方案1:

我认为它完全符合您的需求。

我认为可以忽略性能问题。

synchronize 

您的访问权限可以胜任。为什么要比现在更难。

提示:不会使用数组。我最好使用集合。有一个集合 满足您的需求。

答案 4 :(得分:0)

它取决于线程是仅写入值还是读取它们(例如,将值递增1)。如果他们阅读,那么同步覆盖所有值的区域 - 读取和写入。如果从不同的单元格读取,则第一个变体。如果只是来自同一卖,那么第二个变种。如果没有读取任何值,则根本不需要同步。