如何克隆同步的集合?
想象一个同步集合
:
Set s = Collections.synchronizedSet(new HashSet())
克隆此集合的最佳方法是什么?
优选地,克隆不需要在原始集合上进行任何同步,但要求迭代克隆的集合不需要在原始集合上进行任何同步。
Imagine a synchronized Collection
:
Set s = Collections.synchronizedSet(new HashSet())
What's the best approach to clone this Collection?
It's prefered that the cloning doesn't need any synchronization on the original Collection but required that iterating over the cloned Collection does not need any synchronization on the original Collection.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在同步块内使用复制构造函数:
如果您还需要同步副本,请再次使用
Collections.synchronizedSet(..)
。根据彼得的评论 - 您需要在原始集的同步块中执行此操作。 的文档
synchronizedSet
明确说明了这一点:Use a copy-constructor inside a synchronized block:
If you need the copy to be synchronized as well, then use
Collections.synchronizedSet(..)
again.As per Peter's comment - you'll need to do this in a synchronized block on the original set. The documentation of
synchronizedSet
is explicit about this:使用同步集时,请务必了解访问集中的每个元素都会产生同步开销。
Collections.synchronizedSet()
只是用一个 shell 包装您的集合,强制每个方法同步。可能不是你真正想要的。ConcurrentSkipListSet
将在多线程环境中为您提供更好的性能,其中多个线程将写入该集合。ConcurrentSkipListSet
将允许您执行以下操作:使用集合的克隆进行快照处理并不罕见。如果这就是您所追求的,您可以添加一些代码来处理该项目已被处理的情况。包含在多个副本集中的偶然对象所涉及的开销通常小于使用
Collections.concurrentSet()
的一致开销。编辑:我刚刚注意到 ConcurrentSkipListSet 是 Cloneable 的,并提供了一个线程安全的
clone()
方法。我改变了我的答案,因为我真的相信这是最好的选择——而不是因为Collections.concurrentSet()
而失去可扩展性和性能。When using synchronized sets, do understand that you will incur synchronization overhead accessing every element in the set. The
Collections.synchronizedSet()
merely wraps your set with a shell that forces every method to be synchronized. Probably not what you really intended. AConcurrentSkipListSet
will give you better performance in a multithreaded environment where multiple threads will be writing to the set.The
ConcurrentSkipListSet
will allow you to perform the following:It's not uncommon to use a clone of a set for snapshot processing. If that's what you are after, you might add a little code to handle the case where the item is already processed. The overhead involved with the occasional object included in more than one copy set is usually less than the consistent overhead of using
Collections.concurrentSet()
.EDIT: I just noticed that ConcurrentSkipListSet is Cloneable and provides a threadsafe
clone()
method. I changed my answer because I really believe this is the best option--instead of losing scalability and performance toCollections.concurrentSet()
.您可以通过执行以下操作来避免同步集合,从而避免在原始集合上公开迭代器。
从 Collections.SynchronizedCollection 进行编辑
正如您所看到的,在执行操作的整个过程中都保持锁定。这样就获得了数据的安全副本。内部是否使用 Iterator 并不重要。返回的数组可以以线程安全的方式使用,因为只有本地线程拥有对其的引用。
注意:如果您想避免这些问题,我建议您使用 2004 年 Java 5.0 中添加的并发库中的 Set。我还建议您使用泛型,因为这可以使您的集合更加类型安全。
You can avoid synchronizing the set by doing the following which avoids exposing an Iterator on the original set.
EDIT From Collections.SynchronizedCollection
As you can see, the lock is held for the entire time the operation is performed. As such a safe copy of the data is taken. It doesn't matter if an Iterator is used internally. The array returned can be used in a thread safe manner as only the local thread has a reference to it.
NOTE: If you want to avoid these issues I suggest you use a Set from the concurrency library added in Java 5.0 in 2004. I also suggest you use generics as this can make your collections more type safe.