我对ArrayList安全发布感到怀疑。
我有代码:
private final Map<Long, SomeStuff> map = new ConcurrentHashMap<>();
//Called by Thread 1
public void write() {
List list = new ArrayList<>();
for (int i = 0; i <100 ; i++) {
list.add(new SomeStuff(i))
}
map.put(1L,list)
}
// Called by Thread 2
public void read() {
List list = map.get(1L);
}
map.get(1L)的ivocation是否会使ArrayList返回正确的状态(例如具有正确的大小)?
ArrayList的元素怎么样?元素是否会安全发布?
我注意到ConcurrentHashMap.put
受到节点锁定的保护,将被修改,但ConcurrentHashMap.get
执行Unsafe.getObjectVolatile
。
我认为ArrayList可能发布不安全
谢谢!
答案 0 :(得分:1)
ConcurrentHashMap将是线程安全的,但不是ArrayList
表示如果读者在作者get
调用之前调用put
,则结果将为null
。如果作者在读者的get
电话前拨打电话,那么结果将是List object
因此,如果您将项目添加到列表(下面的代码)
for (int i = 0; i <100 ; i++) {
list.add(new SomeStuff(i))
}
在put
之前它是正常的,因为无法从阅读器访问列表
但是如果在put
之后它可以从阅读器访问并导致读写器同时读取或写入ArrayList。这可能会导致问题,因为ArrayList不是线程安全的。
答案 1 :(得分:0)
简答:是的,ArrayList对象将与其元素一起安全发布。
您通常不应该查看类的源代码并自己做出有关线程安全性的任何结论,但您应该依赖于类/接口javadoc中给出的保证。我强烈推荐这本书&#34; Java Concurrency in Practice&#34;详细阐述了这些方法。
ConcurrentMap(由ConcurrentHashMap实现)接口状态:
内存一致性效果:与其他并发集合一样,在将对象作为键或值放入ConcurrentMap之前的线程中的操作发生在从另一个线程中的ConcurrentMap访问或删除该对象之后的操作之前。
这意味着在&#34; put&#34;之前发生的任何事情是一个线程,可以看到&#34; get&#34;然后在同一个对象上。这意味着,在&#34; get&#34;在&#34; put&#34;之后发生然后你的第二个线程会看到一个好的&#34; ArrayList对象及其所有元素。
以下是一份不是安全出版物的说明,只是要记住的事情:
ArrayList本身(可能还有你的元素&#39;类)不是线程安全的。但只要你不从其他线程修改这些对象,你就可以使用它。如&#34; Java Concurrency in Practice&#34;书 - 这是#34; Serial Thread Confinement&#34;这意味着您可以安全地将非线程安全对象从一个线程发布到另一个线程,从而转移&#34;所有权&#34;从一个线程到一个线程,从而使对象&#34;线程受限&#34;在特定的时间点。正如我所说的那样,只有在确保不从其他地方修改它时才适用。