是包含java.util.List线程安全的方法吗?

时间:2014-07-13 09:35:44

标签: java multithreading arraylist

我将java.util.List声明如下:

private static List<String> extensions = null;

始终由单线程填充。

但是多个线程可以同时调用contains(E e)上的方法extensions

线程安全吗?

3 个答案:

答案 0 :(得分:3)

  

列表在启动时由单个线程填充,之后无法修改。现在包含线程安全吗?

如果您正在谈论ArrayList<T>,正如标签所示,那么是。谈论List<T>的线程安全性是没有意义的,因为接口没有实现。

观看arraylist的实现(here),您可以看到它只读取共享状态,但它不会写任何内容。

小心:

  1. 您的字段属于List<T>类型。您能否保证该字段上存储的变量的运行时类型始终为ArrayList<T>
  2. 更重要的问题是:文档该方法是否是线程安全的?如果它没有,Java的未来版本可能会使它踩踏不安全,这不会被认为是一次重大改变。

  3. 如果其中一个线程正在插入数据而另一个线程正在调用Contains,那么这不是线程安全的。考虑add的实施:

    public void add(int index, E element) {
         rangeCheckForAdd(index);
    
         ensureCapacity(size+1);  // Increments modCount!!
         System.arraycopy(elementData, index, elementData, index + 1,
                          size - index);
         elementData[index] = element;
         size++;
    }
    

    假设您有一个包含4个元素的列表,其内部数组的容量为6.内部数组看起来像{a, b, c, d, null, null},私有字段size将设置为4,以便分隔列表的边界。

    如果我现在在{2}处插入x,那么会发生什么:

    1. arraycopy会将cd向右移动,如此{a, b, c, c, d, null}
    2. 下一行将插入x{a, b, x, c, d, null}
    3. 下一行会将size增加到5,更新列表的边界。
    4. 请注意,如果您在步骤1和3之间的列表中调用Contains(d),将返回false。这是因为size仍然设置为4,并且列表显示为包含{a,b,c,c}{d,null}将被忽略。

答案 1 :(得分:1)

  

列表在启动时由单个线程填充,之后无法修改。现在包含线程安全吗?

以这种方式使用的对象被称为&#34;有效地不可变&#34; ---程序允许更改对象,但它没有。 Brian Goetz的书“ Java Concurrency in Practice ”中有一节专门讨论安全发布有效不可变对象http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601

简短的回答(假设我正确记住它)是如果你在构造函数中填充列表,并且如果在构造函数返回之前没有其他线程可以访问列表,那么列表就会被安全地发布。当然,我假设您在列表中放置的项目也是有效的。

&#34;安全发布&#34;意味着其他线程将保证在预期的最终状态下看到列表。如果列表未安全发布,则在不同处理器上运行的线程可能会看到列表的不同版本(可能包括某些版本,其中列表处于不一致状态,当您尝试访问它时可能会使程序崩溃。)

答案 2 :(得分:0)

不,默认情况下List不是线程安全的。 如果你想让它的线程安全。使用Collections.synchronizedList().