在Java中,如果它是只读的,我是否需要声明我的集合是否已同步?

时间:2008-09-30 09:16:49

标签: java multithreading synchronization web-applications

当我的J2EE webapp启动时,我一次填充一个集合。 然后,几个线程可以同时访问它,但只能读取它。

我知道使用同步集合对于并行写入是强制性的,但我是否还需要它来进行并行读取?

5 个答案:

答案 0 :(得分:19)

通常不会,因为在这种情况下您没有更改集合的内部状态。迭代集合时,会创建一个迭代器的新实例,迭代的状态是每个迭代器实例。


除了注意:请记住,通过保留只读集合,您只能阻止对集合本身的修改。每个集合元素仍然可以更改。

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

     

即使线程已启动   在你填满你的收藏之后,你   可能需要同步,因为你的   集合实现可能会改变   即使在阅读时它的内部状态   运营(感谢Michael Bar-Sinai,   我不知道这样的收藏品   存在)。

     

另一篇非常有趣的读物   涵盖的并发主题   主题如发布对象,   能见度等等更详细   是Brian Goetz的书Java Concurrency in Practice

答案 1 :(得分:10)

这取决于读取集合的线程是在填充之前还是之后启动的。如果它们在填充之前已经启动,那么您无法保证(没有同步),这些线程将看到更新的值。

原因是Java内存模型,如果您想了解更多内容,请阅读此链接中的“可见性”部分:http://gee.cs.oswego.edu/dl/cpj/jmm.html

即使在填充集合后启动了线程,也可能需要进行同步,因为即使在读取操作时,集合实现也可能会更改其内部状态(感谢Michael Bar-Sinai,我不知道存在这样的集合在标准JDK中。

关于并发主题的另一个非常有趣的读物是Brian Goetz的书Java Concurrency in Practice,其中更详细地介绍了对象的发布,可见性等主题。

答案 2 :(得分:9)

在一般情况下,你应该。这是因为某些集合在读取期间会更改其内部结构。使用访问顺序的LinkedHashMap就是一个很好的例子。但是,不要只听我的话:

  

在访问顺序链接哈希映射中,仅使用get查询映射是一种结构修改   The Linked hash map's javadoc

如果您完全确定没有缓存,没有收集统计​​信息,没有优化,也没有任何有趣的东西 - 您不需要同步。在这种情况下,我会在集合上放置一个类型约束:不要将集合声明为Map(允许LinkedHashMap),而是将HashMap声明为HashMap(对于纯粹主义者来说,是HashMap的最后一个子类,但也可能是远...)。

答案 3 :(得分:3)

您没有必要,正如其他答案中所解释的那样。如果您想确保您的收藏是只读的,您可以使用:

yourCollection = Collections.unmodifableCollection(yourCollection);

(List,Set,Map和其他集合类型存在类似的方法)

答案 4 :(得分:0)

集合本身没有,但要记住,如果它所拥有的东西也不是不可变的,那些单独的类需要它们自己的同步。