zoukankan      html  css  js  c++  java
  • 003-多线程-JUC集合-Set-CopyOnWriteArrayList

    一、概述

    它是线程安全的无序的集合,可以将它理解成线程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet虽然都继承于共同的父类AbstractSet;但是,HashSet是通过“散列表(HashMap)”实现的,而CopyOnWriteArraySet则是通过“动态数组(CopyOnWriteArrayList)”实现的,并不是散列表。
    和CopyOnWriteArrayList类似,CopyOnWriteArraySet具有以下特性:
    1. 它最适合于具有以下特征的应用程序:Set 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
    2. 它是线程安全的。
    3. 因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大。
    4. 迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等 操作。
    5. 使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。 

      其实它的结构严格意义来说是一个集合,它的底层实现是利用数组,它的上层实现是CopyOnWriteArrayList。

      其次,CopyOnWriteArraySet是一个集合,所以它是不可以放置重复的元素的,它的取重逻辑是在add中体现的。

      最后,CopyOnWriteArraySet是利用CopyOnWriteArrayList来实现的,因为CopyOnWriteArrayList是线程安全的,所以CopyOnWriteArraySet操作也是线程安全的。

    1.1、数据结构

      

    说明
      1. CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合。
      2. CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的。而CopyOnWriteArrayList本质是个动态数组队列,
    所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”! CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet是一个集合,所以它不能有重复集合。因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!
       至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。这个在前一章节介绍CopyOnWriteArrayList时数据结构时,已经进行了说明,这里就不再重复叙述了。

    1.2、示例

    /*
     *   CopyOnWriteArraySet是“线程安全”的集合,而HashSet是非线程安全的。
     *
     *   下面是“多个线程同时操作并且遍历集合set”的示例
     *   (01) 当set是CopyOnWriteArraySet对象时,程序能正常运行。
     *   (02) 当set是HashSet对象时,程序会产生ConcurrentModificationException异常。
     *
     */
    public class CopyOnWriteArraySetTest1 {
    
        // TODO: set是HashSet对象时,程序会出错。
        //private static Set<String> set = new HashSet<String>();
        private static Set<String> set = new CopyOnWriteArraySet<String>();
    
        public static void main(String[] args) {
    
            // 同时启动两个线程对set进行操作!
            new MyThread("ta").start();
            new MyThread("tb").start();
        }
    
        private static void printAll() {
            String value = null;
            Iterator iter = set.iterator();
            while (iter.hasNext()) {
                value = (String) iter.next();
                System.out.print(value + ", ");
            }
            System.out.println();
        }
    
        private static class MyThread extends Thread {
            MyThread(String name) {
                super(name);
            }
    
            @Override
            public void run() {
                int i = 0;
                while (i++ < 10) {
                    // “线程名” + "-" + "序号"
                    String val = Thread.currentThread().getName() + "-" + (i % 6);
                    set.add(val);
                    // 通过“Iterator”遍历set。
                    printAll();
                }
            }
        }
    }

    1.3、使用场景 

    二、源码分析

  • 相关阅读:
    LightOJ 1300 边双联通分量+交错路染色
    HDU 6143 快速幂,组合数
    windows 下fc工具
    HDU 6136 模拟
    HDU 6129 暴力,规律
    UVA Live 7770 模拟
    1096: [ZJOI2007]仓库建设
    1191: [HNOI2006]超级英雄Hero
    3224: Tyvj 1728 普通平衡树
    1208: [HNOI2004]宠物收养所
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11068523.html
Copyright © 2011-2022 走看看