Asa*_*ika 27 java concurrency hashset
如果我在通过Collections.unmodifiableSet()运行它后有一个HashSet实例,它是否是线程安全的?
我问这个,因为Set文档声明它不是,但我只是执行读操作.
Bri*_*ach 41
来自Javadoc:
请注意,此实现不同步.如果多个线程同时访问哈希集,并且至少有一个线程修改了该集,则必须在外部进行同步
阅读不会修改一套,所以你很好.
Mar*_*ers 13
HashSet如果以只读方式使用,将是线程安全的.这并不意味着您传递给的任何 Set Collections.unmodifiableSet()都将是线程安全的.
想象一下这个天真的实现contains缓存最后检查的值:
Object lastKey;
boolean lastContains;
public boolean contains(Object key) {
if ( key == lastKey ) {
return lastContains;
} else {
lastKey = key;
lastContains = doContains(key);
return lastContains;
}
}
Run Code Online (Sandbox Code Playgroud)
显然,这不是线程安全的.
axt*_*avt 11
这将是线程安全的,但仅仅是因为Collections.unmodifiableSet()内部Set以安全的方式(通过final字段)发布目标.
请注意,通常诸如"只读对象始终是线程安全的"之类的语句是不正确的,因为它们没有考虑操作重新排序的可能性.
(理论上)可能的是,由于操作重新排序,在完全初始化对象并填充数据之前,对该只读对象的引用将对其他线程可见.为了消除这种可能性,您需要以安全的方式发布对对象的引用,例如,通过将它们存储在final字段中,就像它一样Collections.unmodifiableSet().
如果不改变它,每个数据结构都是线程安全的.
因为你必须改变HashSet才能初始化它,所以必须在初始化集合的线程和所有读取线程之间进行一次同步.你所要做的仅仅是一个时间.例如,当您将对不可修改集的引用传递给之前从未触及它的新线程时.