如果java集合的所有属性(或项目字段或数据成员)都是线程安全的(CopyOnWriteArraySet
,ConcurrentHashMap
,BlockingQueue
,. ..),我们可以说这个集合是线程安全的吗?
一个例子:
public class AmIThreadSafe {
private CopyOnWriteArraySet thradeSafeAttribute;
public void add(Object o) {
thradeSafeAttribute.add(o);
}
public void clear() {
thradeSafeAttribute.clear();
}
}
在此示例中我们可以说AmIThreadSafe
线程安全吗?
答案 0 :(得分:3)
假设“属性”是指“收集的内容”,则不是。仅仅因为Collection
包含线程安全的项目并不意味着Collection
的实现实现了add()
,clear()
,remove()
等等。线程安全的方式。
答案 1 :(得分:2)
不,因为对象的状态是其所有属性的“总和”。
例如,您可以在对象中使用2个线程安全集合作为属性。此外,您的对象可能依赖于这两个集合之间的某种关联(例如,如果一个对象在一个集合中,它在另一个集合中,反之亦然)。简单地使用2个线程安全的集合将无法确保在所有时间点都存在相关性。您需要在对象中使用其他并发控制,以确保此约束在两个集合中保持不变。由于大多数非平凡对象在其属性中具有某种类型的关联关系,因此使用线程安全集合作为属性不足以使对象成为线程安全的。
答案 2 :(得分:2)
简答:否。
稍微长一点的答案:因为add()和clear()没有以任何方式同步,并且HashSet本身不同步,所以多个线程可能同时存在于其中。
编辑以下评论:啊。现在简短的回答是是,sorta 。 :)
“sorta”(美国俚语,部分意思是顺便说一句)的原因是两个操作可能是原子安全的,但是当组合使用以进行复合操作时是不安全的。
在您给出的示例中,只支持add()和clear(),这不可能发生。
但是在一个更完整的类中,我们将拥有更多的Collection接口,想象一个调用者需要在集合中添加一个条目,如果该集合已经不超过100个条目。
这个调用者想要写一个像这样的方法:
void addIfNotOverLimit (AmIThreadSafe set, Object o, int limit) {
if (set.size() < limit) // ## thread-safe call 1
set.add(o); // ## thread-safe call 2
}
问题是虽然每个调用本身都是线程安全的,但是两个线程可以在addIfNotOverLimit中(或者就此而言,通过另一个方法完全添加),所以线程A会调用size()并得到99,然后调用add (),但在此之前,它可能会被中断,然后线程B可以添加一个条目,现在该集合将超过其限制。
道德?复合操作使“线程安全”的定义更加复杂。
答案 3 :(得分:1)
什么是线程安全?
线程安全只是意味着 对象或类的字段总是如此 保持有效状态,如所观察到的那样 其他对象和类,即使是 由多个线程同时使用。
一个线程安全的对象就是那个 始终保持有效状态,如 通过其他类和对象观察, 即使在多线程环境中也是如此。
根据API文档,您必须使用此功能来确保线程安全:
synchronizedCollection(Collection c)
Returns a synchronized (thread-safe) collection
backed by the specified collection
读到这一点,我认为你必须使用上面的函数来确保线程安全的Collection。但是,您不必将它们用于所有集合,并且有更快的集合,这些集合是线程安全的,例如ConcurrentHashMap。 CopyOnWriteArraySet的基本特性可确保线程安全操作。