CopyOnWriteArraySet何时有用于实现线程

Java ,存在名为ConcurrentHashMap的线程安全版本HashMap和名为ConcurrentSkipListMap的线程安全版本TreeMap,但没有用于HashSet的ConcurrentHashSet

相反,通常有4种方法可以使用线程安全的Set

  • Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
  • Set<String> s = Collections.synchronizedSet(new HashSet<String>());
  • ConcurrentSkipListSet<E>
  • CopyOnWriteArraySet<E>
  • 1使用ConcurrentHashMap keySet()来实现Set和线程安全。

    2使用synchronized方式,似乎不建议这种方式。

    3基于ConcurrentSkipListMap并被广泛使用。

    4是基于的CopyOnWriteArrayList,从而它共享相同的基本性质CopyOnWriteArrayList 。 以下是从CopyOnWriteArraySet doc中选择:http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArraySet.html

  • 它最适合于集合大小通常很小的应用程序,只读操作大大超过了可变操作,并且您需要防止遍历期间线程之间的干扰。
  • 它是线程安全的。
  • 突变操作(添加,设置,删除等)很昂贵,因为它们通常需要复制整个底层阵列。
  • 迭代器不支持可变删除操作。
  • 遍历迭代器速度快,不会受到来自其他线程的干扰。
  • 迭代器构建时,迭代器依赖于数组的不变快照。
  • 由于1和3是常用的,为什么CopyOnWriteArraySet存在? CopyOnWriteArraySet何时有用?

    补充: CopyOnWriteArraySet是基于CopyOnWriteArrayListList数据结构中的contains操作是O(n),而Set数据结构是用于高性能contains操作的,有谁能解释这一点吗?


    当您有一个用于线程安全集合的小组元素时,它非常有用。

    一个例子是一组听众。 您需要确保唯一性并有效地对它们进行迭代。

    BTW CopyOnWriteArraySet具有每个参考基础上最低的开销。 它可能只有其他馆藏的1/6。 如果你有很多它们,这是特别有用的。

    而Set数据结构是用于高性能包含操作的,有谁能解释这一点?

    COWAS在内存方面效率更高,而且contains内容比其他内容更快。 什么是“高性能”取决于用例。


    写入时复制结构在功能上是不可变的。

    Java在某一时刻对于可写结构(例如集合)提供不可变视图有一个非常糟糕的故事。 例如,如果你有一个成员,并且你公开地返回它,调用者可以转过来编辑它,因此编辑你的对象的内部状态! 但你还能做什么,在从任何公共职能返回之前复制整个事情? 这将是毫无意义的缓慢。

    这是Java历史上早期的故事。 他们几乎完全依赖于不可变的对象(字符串是一个例子)。 集合是这种模式的一个例外,因此从封装的角度来看是有问题的。 当添加CopyOnWriteArraySet时, unmodifiableCollectionunmodifiableSet CopyOnWriteArraySet尚不存在(虽然unmodifiableCollection已经在很大程度上解决了这个问题,但我仍然发现它比其他语言提供的更麻烦的解决方案,特别是在使用自定义数据结构时)。 所以这可能解释了首先创建CopyOnWriteArraySet的最大动机。 您可以返回CopyOnWriteArraySet而不用担心别人会修改对象的内部状态,也不会浪费时间制作不必要的副本。

    写时复制是几年前的一种时尚,但对于多线程编程而言,这是一个非常低效的想法,并且效率低于其他模型。 从你发布的文档中,他们通过创建线程本地快照来加快迭代,这意味着他们花费内存来弥补。 所以只要你的数据很小就可以使用它,因为内存快照不会浪费太多内存。


    测试代码:

    Set<String> a = new CopyOnWriteArraySet<String>();
        for(int i=0;i<10;i++) {
            a.add("str" + i);
        }
        boolean flag = true;
        long t1 = System.currentTimeMillis();
        for(int i=0;i<200000;i++) {
            flag = a.contains("str" + i);
        }
        System.out.println(System.currentTimeMillis() - t1);
    
        Set<String> b = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
        for(int i=0;i<10;i++) {
            b.add("str" + i);
        }
        t1 = System.currentTimeMillis();
        for(int i=0;i<200000;i++) {
            flag = b.contains("str" + i);
        }
        System.out.println(System.currentTimeMillis() - t1);
    

    显示CopyOnWriteArraySetCollections.newSetFromMap慢。 由于测试用例是一个只读操作的非常小的Set ,因此CopyOnWriteArraySet看起来不会更好。

    链接地址: http://www.djcxy.com/p/76117.html

    上一篇: When is CopyOnWriteArraySet useful to achieve thread

    下一篇: How the iterator is failsafe in concurrent hash map