如何克隆同步的集合?

发布于 2024-10-09 19:09:12 字数 203 浏览 0 评论 0原文

想象一个同步集合

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陪我终i 2024-10-16 19:09:12

在同步块内使用复制构造函数:

synchronized (s) {
    Set newSet = new HashSet(s); //preferably use generics
}

如果您还需要同步副本,请再次使用Collections.synchronizedSet(..)

根据彼得的评论 - 您需要在原始集的同步块中执行此操作。 的文档synchronizedSet 明确说明了这一点:

用户在迭代返回的集合时必须手动同步它

Use a copy-constructor inside a synchronized block:

synchronized (s) {
    Set newSet = new HashSet(s); //preferably use generics
}

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:

It is imperative that the user manually synchronize on the returned set when iterating over it

玩世 2024-10-16 19:09:12

使用同步集时,请务必了解访问集中的每个元素都会产生同步开销。 Collections.synchronizedSet() 只是用一个 shell 包装您的集合,强制每个方法同步。可能不是你真正想要的。 ConcurrentSkipListSet 将在多线程环境中为您提供更好的性能,其中多个线程将写入该集合。

ConcurrentSkipListSet 将允许您执行以下操作:

Set newSet = s.clone();//preferably use generics

使用集合的克隆进行快照处理并不罕见。如果这就是您所追求的,您可以添加一些代码来处理该项目已被处理的情况。包含在多个副本集中的偶然对象所涉及的开销通常小于使用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. A ConcurrentSkipListSet 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:

Set newSet = s.clone();//preferably use generics

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 to Collections.concurrentSet().

乖乖兔^ω^ 2024-10-16 19:09:12

您可以通过执行以下操作来避免同步集合,从而避免在原始集合上公开迭代器。

Set newSet = new HashSet(Arrays.asList(s.toArray())); 

从 Collections.SynchronizedCollection 进行编辑

public Object[] toArray() {
    synchronized(mutex) {return c.toArray();}
}

正如您所看到的,在执行操作的整个过程中都保持锁定。这样就获得了数据的安全副本。内部是否使用 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.

Set newSet = new HashSet(Arrays.asList(s.toArray())); 

EDIT From Collections.SynchronizedCollection

public Object[] toArray() {
    synchronized(mutex) {return c.toArray();}
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文