【发布时间】:2010-09-14 05:15:52
【问题描述】:
当我的 J2EE webapp 启动时,我会一次性填充一个集合。 然后,多个线程可以同时访问它,但只是为了读取它。
我知道并行写入必须使用同步集合,但并行读取仍然需要它吗?
【问题讨论】:
标签: java multithreading synchronization web-applications
当我的 J2EE webapp 启动时,我会一次性填充一个集合。 然后,多个线程可以同时访问它,但只是为了读取它。
我知道并行写入必须使用同步集合,但并行读取仍然需要它吗?
【问题讨论】:
标签: java multithreading synchronization web-applications
这取决于读取您的集合的线程是在您填充它之前还是之后启动的。如果它们在您填充它之前启动,您无法保证(没有同步)这些线程将永远看到更新的值。
原因是 Java 内存模型,如果您想了解更多信息,请阅读此链接的“可见性”部分:http://gee.cs.oswego.edu/dl/cpj/jmm.html
即使在填充集合后启动线程,您也可能需要同步,因为即使在读取操作时,集合实现也可能更改其内部状态(感谢 Michael Bar-Sinai,我不知道此类集合存在于标准JDK)。
关于并发主题的另一本非常有趣的读物是 Brian Goetz 的书 Java Concurrency in Practice。
【讨论】:
通常不会,因为在这种情况下您不会更改集合的内部状态。当您对集合进行迭代时,会创建一个新的迭代器实例,并且迭代的状态是每个迭代器实例。
旁注:请记住,保留只读集合只是防止对集合本身进行修改。每个集合元素仍然是可变的。
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 answser 的重要注意事项。
这取决于线程是否 开始阅读您的收藏 在填充之前或之后。如果 他们在你填满它之前就开始了, 你没有任何保证(没有 同步),这些线程 将永远看到更新的值。
原因是 Java 内存 型号,如果您想了解更多信息,请阅读 此链接的“可见性”部分: http://gee.cs.oswego.edu/dl/cpj/jmm.html
即使线程已启动 在你填满你的收藏后,你 可能必须同步,因为您的 收集实施可能会改变 即使在读取时它的内部状态 运营(感谢Michael Bar-Sinai, 我不知道这样的收藏 存在)。
另一个非常有趣的阅读 涵盖的并发主题 诸如发布对象之类的主题, 能见度等更详细 是 Brian Goetz 的书Java Concurrency in Practice。
【讨论】:
在一般情况下,您应该这样做。这是因为某些集合在读取期间会更改其内部结构。使用访问顺序的 LinkedHashMap 就是一个很好的例子。但不要只相信我的话:
在access-ordered linked hash maps中,仅仅用get查询map是一种结构修改 The Linked hash map's javadoc
如果您完全确定没有缓存、没有收集统计信息、没有优化、根本没有有趣的东西 - 您不需要同步。在那种情况下,我会对集合设置类型约束:不要将集合声明为 Map(这将允许 LinkedHashMap),而是声明为 HashMap(对于纯粹主义者来说,是 HashMap 的最终子类,但这可能也是远...)。
【讨论】:
如其他答案中所述,您不必这样做。如果你想确保你的收藏是只读的,你可以使用:
yourCollection = Collections.unmodifableCollection(yourCollection);
(List、Set、Map等集合类型也有类似的方法)
【讨论】:
集合本身不是,但请记住,如果它所拥有的也不是不可变的,那么这些单独的类需要它们自己的同步。
【讨论】: