我有一个长度为100的数组。我需要在Multi Threaded环境中使用它。总共有10个线程访问数组。可能有两个线程t1
& t2
希望一次写入相同的索引。
Object[] data = new Object[100];
实施此目的的最佳方法是什么。
解决方案1:
只有一个线程可以写入数组。即使t1
和t2
线程想要写入不同的索引,也必须等待。即使我们可以使用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 :(得分: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
或任何类似的队列,例如
答案 3 :(得分:0)
我会选择解决方案1:
我认为它完全符合您的需求。
我认为可以忽略性能问题。
synchronize
您的访问权限可以胜任。为什么要比现在更难。
提示:我不会使用数组。我最好使用集合。有一个集合 满足您的需求。
答案 4 :(得分:0)
它取决于线程是仅写入值还是读取它们(例如,将值递增1)。如果他们阅读,那么同步覆盖所有值的区域 - 读取和写入。如果从不同的单元格读取,则第一个变体。如果只是来自同一卖,那么第二个变种。如果没有读取任何值,则根本不需要同步。