了解 java 的同步集合
understanding java's synchronized collections
我正在阅读 java 官方 doc 关于包装器实现的内容,它们是 Collections 中用于获取同步集合的静态方法,例如: List<Type> list = Collections.synchronizedList(new ArrayList<Type>());
...
我不明白的是以下内容(我引用 java 文档):
A collection created in this fashion is every bit as thread-safe as a normally synchronized collection, such as a Vector.
In the face of concurrent access, it is imperative that the user manually synchronize on the returned collection when iterating over it. The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation...
怎么可能每一位都是线程安全的需要在迭代时手动同步??
这里没有矛盾:从 synchronizedXyz
返回的集合与直接可用的同步集合有同样的缺点,即需要在迭代集合时手动同步。
外部迭代的问题无法通过更好的class设计来解决,因为迭代一个集合本质上需要多次调用它的方法(see this Q&A for detailed explanation)。
请注意,从 Java 1.8 开始,您可以使用同步集合的 forEach
方法进行迭代,而无需额外同步 *。这是 thread-safe,还有额外的好处; see this Q&A for details.
这与外部迭代不同的原因是 forEach
集合内部的实现负责为您同步迭代。
它是线程安全的,因为它的每个单独方法都是线程安全的,但是如果您对集合执行复合操作,那么您的代码就有并发问题的风险。
例如:
List<String> synchronizedList = Collections.synchronizedList(someList);
synchronizedList.add(whatever); // this is thread safe
单个方法 add()
是线程安全的,但如果我执行以下操作:
List<String> synchronizedList = Collections.synchronizedList(someList);
if(!synchronizedList.contains(whatever))
synchronizedList.add(whatever); // this is not thread safe
if-then-add 操作不是线程安全的,因为某些其他线程可能在 contains()
检查后将 whatever
添加到列表中。
我正在阅读 java 官方 doc 关于包装器实现的内容,它们是 Collections 中用于获取同步集合的静态方法,例如: List<Type> list = Collections.synchronizedList(new ArrayList<Type>());
...
我不明白的是以下内容(我引用 java 文档):
A collection created in this fashion is every bit as thread-safe as a normally synchronized collection, such as a Vector. In the face of concurrent access, it is imperative that the user manually synchronize on the returned collection when iterating over it. The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation...
怎么可能每一位都是线程安全的需要在迭代时手动同步??
这里没有矛盾:从 synchronizedXyz
返回的集合与直接可用的同步集合有同样的缺点,即需要在迭代集合时手动同步。
外部迭代的问题无法通过更好的class设计来解决,因为迭代一个集合本质上需要多次调用它的方法(see this Q&A for detailed explanation)。
请注意,从 Java 1.8 开始,您可以使用同步集合的 forEach
方法进行迭代,而无需额外同步 *。这是 thread-safe,还有额外的好处; see this Q&A for details.
这与外部迭代不同的原因是 forEach
集合内部的实现负责为您同步迭代。
它是线程安全的,因为它的每个单独方法都是线程安全的,但是如果您对集合执行复合操作,那么您的代码就有并发问题的风险。
例如:
List<String> synchronizedList = Collections.synchronizedList(someList);
synchronizedList.add(whatever); // this is thread safe
单个方法 add()
是线程安全的,但如果我执行以下操作:
List<String> synchronizedList = Collections.synchronizedList(someList);
if(!synchronizedList.contains(whatever))
synchronizedList.add(whatever); // this is not thread safe
if-then-add 操作不是线程安全的,因为某些其他线程可能在 contains()
检查后将 whatever
添加到列表中。