我将java.util.List声明如下:
private static List<String> extensions = null;
始终由单线程填充。
但是多个线程可以同时调用contains(E e)
上的方法extensions
。
线程安全吗?
答案 0 :(得分:3)
列表在启动时由单个线程填充,之后无法修改。现在包含线程安全吗?
如果您正在谈论ArrayList<T>
,正如标签所示,那么是。谈论List<T>
的线程安全性是没有意义的,因为接口没有实现。
观看arraylist的实现(here),您可以看到它只读取共享状态,但它不会写任何内容。
小心:
List<T>
类型。您能否保证该字段上存储的变量的运行时类型始终为ArrayList<T>
?如果其中一个线程正在插入数据而另一个线程正在调用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
,那么会发生什么:
arraycopy
会将c
和d
向右移动,如此{a, b, c, c, d, null}
x
,{a, b, x, c, d, null}
size
增加到5,更新列表的边界。请注意,如果您在步骤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().