【问题标题】:Cloning ConcurrentHashMap克隆 ConcurrentHashMap
【发布时间】:2016-11-19 22:42:21
【问题描述】:

为什么我不能克隆ConcurrentHashMap

ConcurrentHashMap<String, String> test = new ConcurrentHashMap<String, String>();
    test.put("hello", "Salaam");

    ConcurrentHashMap<String, String> test2 = (ConcurrentHashMap<String, String> ) test.clone();

    System.out.println(test2.get("hello"));

如果我使用HashMap 而不是ConcurrentHashMap,它可以工作。

【问题讨论】:

  • 因为与HashMap 不同,ConcurrentHashMap 没有实现Cloneable。突出的事实是,您的代码无法编译,即该方法不可用!!!
  • @Andreas:尽管有这个名字,实现Cloneable 并不意味着你支持clone,支持clone 并不要求你实现CloneableCloneable 实际上并没有 clone 作为公共方法。这是clone 设计的奇怪缺陷之一。
  • 支持clone 确实需要实现Cloneable 接口@user2357112。 “在未实现 Cloneable 接口的实例上调用 Object 的 clone 方法会导致抛出异常 CloneNotSupportedException。” - docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html
  • @LewBloch:是的,但是如果你在你的clone 实现中不使用Object::clone(这有时是合理的),你就不需要实现Cloneable。它甚至不像Comparable,如果你实现compareTo 而不实现Comparable,你就会失去所有采用Comparable 参数的库方法。没有使用clone 的内容需要Cloneable,因为你不能cloneCloneable

标签: java clone concurrenthashmap


【解决方案1】:

AbstractMap 上的clone() 方法不是用来复制的,它是一个内部方法,注意受保护的关键字。

protected Object clone() throws CloneNotSupportedException {

HashMap 恰好有一个公共的clone(), 但这并不意味着你应该使用它,Effective Java: Analysis of the clone() method 会进一步讨论这个问题

创建集合副本的一种更灵活的方法是通过复制构造函数。这些具有从任何其他创建任何 Map 实现的优势。

/**
 * Creates a new map with the same mappings as the given map.
 *
 * @param m the map
 */
public ConcurrentHashMap(Map<? extends K, ? extends V> m) {

例如

ConcurrentHashMap<String, String> original = new ConcurrentHashMap<String, String>();
original.put("hello", "Salaam");

Map<String, String> copy = new ConcurrentHashMap<>(original);
original.remove("hello");
System.out.println(copy.get("hello"));

【讨论】:

  • 您建议的方法实际上是线程安全的吗?请注意,如果原始映射是并发哈希映射。然后您尝试通过新的 HashMap(collection) 克隆它。代码将进入 for (Map.Entry extends K, ? extends V> e : m.entrySet()) 循环因此,如果同时有人访问您的并发哈希图并获取与他们配对的键值,您可以迭代元素时出现问题。并且并发哈希映射构造函数的实现看起来并不安全......它只是循环原始映射的条目集。所以再见了爆炸。
  • 根据stackoverflow.com/questions/3768554/…。其实应该没问题的。
【解决方案2】:

更优雅的方式是执行深度克隆。 如果您确实执行了深度克隆,那么可能存在您只复制存储在并发 hashmap 中的引用而不是实际对象的情况。这就是为什么在这种情况下,在克隆对象图中的对象时首选深度克隆。进行深度克隆的最简单方法之一是使用 apache 通用语言库 - SerializationUtils#clone。

<dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>

您可以使用 SerializationUtils 类的克隆 api 进行深度克隆,如下所示 -

ConcurrentHashMap<String, Vertex> transposeVertexMap = (ConcurrentHashMap<String, Vertex>) SerializationUtils.clone(vertexMap);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    相关资源
    最近更新 更多