在爪哇,我需要声明,我的收藏同步,如果它是只读的?
-
02-07-2019 - |
题
我填的一个集合中的一个单一的时候,我J2EE网络应用程序的开始。然后,有几个螺纹可以访问它在同一时间,但仅仅读它。
我知道利用一个同步的集合是强制性的相似之处写信但我还需要它的相似之处?
解决方案
通常不会,因为在这种情况下您没有更改集合的内部状态。迭代集合时,会创建一个迭代器的新实例,迭代的状态是每个迭代器实例。
除了注意:请记住,通过保留只读集合,您只能阻止对集合本身的修改。每个集合元素仍然可以更改。
class Test {
public Test(final int a, final int b) {
this.a = a;
this.b = b;
}
public int a;
public int b;
}
public class Main {
public static void main(String[] args) throws Exception {
List<Test> values = new ArrayList<Test>(2);
values.add(new Test(1, 2));
values.add(new Test(3, 4));
List<Test> readOnly = Collections.unmodifiableList(values);
for (Test t : readOnly) {
t.a = 5;
}
for (Test t : values) {
System.out.println(t.a);
}
}
}
输出:
5
5
@WMR回答者的重要注意事项。
这取决于线程是否是 正在阅读你的收藏 在填写之前或之后。如果 它们是在你填充它之前开始的, 你没有保证(没有 同步),即这些线程 将永远看到更新的值。
原因是Java Memory 模特,如果你想了解更多阅读 部分“可见性”在这个链接: http://gee.cs.oswego.edu/dl/cpj/jmm。 HTML
即使线程已启动 在你填满你的收藏之后,你 可能需要同步,因为你的 集合实现可能会改变 即使在阅读时它的内部状态 操作(谢谢迈克尔· 酒吧 - 西奈, 我不知道这样的收藏品 存在)。
另一篇非常有趣的读物 涵盖的并发主题 主题如发布对象, 能见度等等更详细 是Brian Goetz的书 Java 并发性 实践。
其他提示
这取决于读取集合的线程是在填充之前还是之后启动的。如果它们在填充之前已经启动,那么您无法保证(没有同步),这些线程将看到更新的值。
原因是Java内存模型,如果你想了解更多,请阅读“可见性”部分。在此链接: http://gee.cs.oswego.edu/dl/ cpj / jmm.html
即使在填充集合后启动了线程,也可能需要进行同步,因为即使在读取操作时,集合实现也可能会更改其内部状态(感谢 Michael Bar-Sinai ,我不知道这样的收藏存在于标准JDK中。
关于并发主题的另一个非常有趣的读物,更详细地介绍了对象发布,可见性等主题,是Brian Goetz的书 Java Concurrency in Practice 。
在一般情况下,你应该。这是因为一些集合的变化他们的内部结构过程中读取。一LinkedHashMap,使访问顺序是一个很好的例子。但不只是我的话:
在访问订联散列的地图,只是查询的地图那是结构上的修改 链接的散列地图的如果是的话,为什么不试
如果你是绝对肯定的是,没有高速缓存,没有收集统计数据,没有优化,没有滑稽的东西-你不需要同步。在这种情况下,我会把一类约束的收集:不申报收集作为一个地图(它将允许LinkedHashMap)但是,如哈希(对于纯粹主义者,一个最终的子类哈希,但是可能把它太远...).
您没有必要,正如其他答案中所解释的那样。如果您想确保您的收藏是只读的,您可以使用:
yourCollection = Collections.unmodifableCollection(yourCollection);
(List,Set,Map和其他集合类型存在类似的方法)
集合本身没有,但要记住,如果它所拥有的东西也不是不可变的,那些单独的类需要它们自己的同步。