我想要具有线程安全的同步集合(列表或集合)。我的集合将包含Variable类的对象,其中包含name,value等文件。现在假设两个线程想要修改该列表中的对象(添加新的或删除现有的对象)。这是最好的解决方案吗?我在stackoverflow上找到了这样的smth。
List<Variable> varList = Collections.synchronizedList(new ArrayList<Variable>());
void processList(List<Variable> varList, String name)
{
synchronized(varList) {
varList.stream().filter(o -> o.getName().equals(name)).findFirst().ifPresent(o -> o.setValue(100));
// or
varList.remove(0);
// or
varList.add(new Variable());
}
}
它会没有任何问题吗?或者有更好的解决方案吗?
答案 0 :(得分:2)
最佳解决方案取决于用例。如果您需要一个有序的randomacces Collection,那么有3个选项。
1)您描述的那个(Synchronized List)。它将执行与底层Collection类型一样快的速度,使用drawBack将整个Collection锁定在Thread访问上。
除了Iterator实现默认情况下不是Threadsafe,因此需要额外的threadSafty度量。 (itetator通常用于forEach, clear
和其他默认(java 8)实现)。
2) CopyOnWriteArrayList。这是JDK中唯一的ThreadSafe(包括具有快照功能的迭代器)randomAcces List。
缺点是它在添加/删除数据时复制数据。对于较小的集合,这可能不是问题,尽管基本规则是,当有更多的“读取”时,它是最好的解决方案。行动而非写作#39;动作。
3) Vector。这对于阅读&#39;而言有点慢。与CopyOnWriteList相对应的动作,尽管它的“写入”#39;机制不需要制作支持数据的副本。
这个问题的一个缺点是Iterator也不是ThreadSafe。与同步列表的区别在于,当有更多的线程访问集合时,它将比SynchronizedList执行得更好。
Sumarry:
答案 1 :(得分:1)
我会做得更简单。您只需要在同步块内的列表上进行所有修改,使用与锁相同的列表对象。
例如,假设您有列表
List<Variable> varList;
已经填充了Variable对象。现在,每次要在代码中访问或修改此List时,必须使用varList上的synchronized块锁定包含这段代码,如下所示:
synchronized(varList) {
// here you access, add, delete, or modify the List
// for example:
if(varList.get(1) == 3) {
varList.remove(1);
varList.add(new Variable());
}
}
为此,您必须确保两个线程正在使用相同 varList,这是,varList是两个线程的共享变量(例如字段或静态变量) 。您还可以使用任何其他新对象作为锁,但始终确保它是两个线程的公共对象(不是两个具有相同名称的变量引用内存中的不同对象)。 但我更喜欢使用列表本身作为锁,所以它使代码更清晰,我知道在该块中我正在修改该列表。