【从入门到放弃-Java】并发编程-JUC-CopyOnWriteArraySet

简介: 前言CopyOnWriteArraySet也是JUC下常用容器,其底层实现是基于CopyOnWriteArrayList的,关于CopyOnWriteArrayList的详情可以查看【从入门到放弃-Java】并发编程-JUC-CopyOnWriteArrayList,接下来我们看下源码。

前言

CopyOnWriteArraySet也是JUC下常用容器,其底层实现是基于CopyOnWriteArrayList的,关于CopyOnWriteArrayList的详情可以查看【从入门到放弃-Java】并发编程-JUC-CopyOnWriteArrayList,接下来我们看下源码。

CopyOnWriteArraySet

CopyOnWriteArraySet

/**
 * Creates an empty set.
 */
 //简单粗暴,只有一个成员变量al,是CopyOnWriteArrayList类型的,初始化时,new一个CopyOnWriteArrayList赋值给al。
public CopyOnWriteArraySet() {
    al = new CopyOnWriteArrayList<E>();
}

/**
 * Creates a set containing all of the elements of the specified
 * collection.
 *
 * @param c the collection of elements to initially contain
 * @throws NullPointerException if the specified collection is null
 */
public CopyOnWriteArraySet(Collection<? extends E> c) {
    if (c.getClass() == CopyOnWriteArraySet.class) {
        @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
            (CopyOnWriteArraySet<E>)c;
        al = new CopyOnWriteArrayList<E>(cc.al);
    }
    else {
        al = new CopyOnWriteArrayList<E>();
        al.addAllAbsent(c);
    }
}

add

/**
 * Adds the specified element to this set if it is not already present.
 * More formally, adds the specified element {@code e} to this set if
 * the set contains no element {@code e2} such that
 * {@code Objects.equals(e, e2)}.
 * If this set already contains the element, the call leaves the set
 * unchanged and returns {@code false}.
 *
 * @param e element to be added to this set
 * @return {@code true} if this set did not already contain the specified
 *         element
 */
public boolean add(E e) {
    //调用CopyOnWriteArrayList的addIfAbsent方法。
    return al.addIfAbsent(e);
}

//看下CopyOnWriteArrayList的addIfAbsent方法如何实现。
/**
 * Appends the element, if not present.
 *
 * @param e element to be added to this list, if absent
 * @return {@code true} if the element was added
 */
public boolean addIfAbsent(E e) {
    Object[] snapshot = getArray();
    //先查找e是否在存在,不存在的话 调用addIfAbsent(E e, Object[] snapshot)方法
    return indexOfRange(e, snapshot, 0, snapshot.length) < 0
        && addIfAbsent(e, snapshot);
}

/**
 * A version of addIfAbsent using the strong hint that given
 * recent snapshot does not contain e.
 */
private boolean addIfAbsent(E e, Object[] snapshot) {
    //加锁
    synchronized (lock) {
        Object[] current = getArray();
        int len = current.length;
        //加锁后check下快照是否被改动
        if (snapshot != current) {
            //如果改动过,则判断改动后的数组是否包含要添加的元素,如果有的话,则返回失败
            // Optimize for lost race to another addXXX operation
            int common = Math.min(snapshot.length, len);
            for (int i = 0; i < common; i++)
                if (current[i] != snapshot[i]
                    && Objects.equals(e, current[i]))
                    return false;
            if (indexOfRange(e, current, common, len) >= 0)
                    return false;
        }
        //验证数组中没有此元素,则在末尾添加。
        Object[] newElements = Arrays.copyOf(current, len + 1);
        newElements[len] = e;
        //替换原数组。
        setArray(newElements);
        return true;
    }
}

addAll

/**
 * Adds all of the elements in the specified collection to this set if
 * they're not already present.  If the specified collection is also a
 * set, the {@code addAll} operation effectively modifies this set so
 * that its value is the <i>union</i> of the two sets.  The behavior of
 * this operation is undefined if the specified collection is modified
 * while the operation is in progress.
 *
 * @param  c collection containing elements to be added to this set
 * @return {@code true} if this set changed as a result of the call
 * @throws NullPointerException if the specified collection is null
 * @see #add(Object)
 */
public boolean addAll(Collection<? extends E> c) {
    //直接调用CopyOnWriteArrayList的addAllAbsent方法。
    return al.addAllAbsent(c) > 0;
}

/**
 * Appends all of the elements in the specified collection that
 * are not already contained in this list, to the end of
 * this list, in the order that they are returned by the
 * specified collection's iterator.
 *
 * @param c collection containing elements to be added to this list
 * @return the number of elements added
 * @throws NullPointerException if the specified collection is null
 * @see #addIfAbsent(Object)
 */
public int addAllAbsent(Collection<? extends E> c) {
    //将要添加的元素变为数组
    Object[] cs = c.toArray();
    if (cs.length == 0)
        return 0;
    //加锁
    synchronized (lock) {
        Object[] es = getArray();
        int len = es.length;
        int added = 0;
        // uniquify and compact elements in cs
        //遍历要添加的数组,如果在List的数组中不存在此元素,则添加到cs数组中
        for (int i = 0; i < cs.length; ++i) {
            Object e = cs[i];
            if (indexOfRange(e, es, 0, len) < 0 &&
                indexOfRange(e, cs, 0, added) < 0)
                cs[added++] = e;
        }
        if (added > 0) {
            Object[] newElements = Arrays.copyOf(es, len + added);
            //将cs数组的前added个元素添加在List数组后面
            System.arraycopy(cs, 0, newElements, len, added);
            //替换原数组
            setArray(newElements);
        }
        return added;
    }
}

remove

/**
 * Removes the specified element from this set if it is present.
 * More formally, removes an element {@code e} such that
 * {@code Objects.equals(o, e)}, if this set contains such an element.
 * Returns {@code true} if this set contained the element (or
 * equivalently, if this set changed as a result of the call).
 * (This set will not contain the element once the call returns.)
 *
 * @param o object to be removed from this set, if present
 * @return {@code true} if this set contained the specified element
 */
public boolean remove(Object o) {
    //直接调用CopyOnWriteArrayList的remove
    return al.remove(o);
}

总结

通过源码分析,我们了解到,CopyOnWriteArraySet主要是依赖CopyOnWriteArrayList来实现各方法的。
因此与CopyOnWriteArrayList一样,更适用于读多写少的并发操作中。
详细原因在【从入门到放弃-Java】并发编程-JUC-CopyOnWriteArrayList中以及解释过了,这里不再赘述。

值得一提的是,常用的非并发容器HashSet,是基于HashMap实现的,利用HashMap中Entry的key做到唯一值,Entry的value是一个不可变静态对象Object。但是JUC中并发Set是却不是基于Map的,学习完这三章并发容器,你能回答这是为什么吗?可以在评论中留言,我们一起探讨下哦~

更多文章

见我的博客:https://nc2era.com

written by AloofJr,转载请注明出处

目录
相关文章
|
1月前
|
Java 编译器 开发者
深入理解Java内存模型(JMM)及其对并发编程的影响
【9月更文挑战第37天】在Java的世界里,内存模型是隐藏在代码背后的守护者,它默默地协调着多线程环境下的数据一致性和可见性问题。本文将揭开Java内存模型的神秘面纱,带领读者探索其对并发编程实践的深远影响。通过深入浅出的方式,我们将了解内存模型的基本概念、工作原理以及如何在实际开发中正确应用这些知识,确保程序的正确性和高效性。
|
18天前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第17天】本文详细介绍了Java编程中Map的使用,涵盖Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的并发处理和性能优化技巧,适合初学者和进阶者学习。
34 3
|
2天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
5天前
|
存储 缓存 安全
Java内存模型(JMM):深入理解并发编程的基石####
【10月更文挑战第29天】 本文作为一篇技术性文章,旨在深入探讨Java内存模型(JMM)的核心概念、工作原理及其在并发编程中的应用。我们将从JMM的基本定义出发,逐步剖析其如何通过happens-before原则、volatile关键字、synchronized关键字等机制,解决多线程环境下的数据可见性、原子性和有序性问题。不同于常规摘要的简述方式,本摘要将直接概述文章的核心内容,为读者提供一个清晰的学习路径。 ####
19 2
|
9天前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
37 5
|
6天前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
18 1
|
12天前
|
Java 数据处理 开发者
Java多线程编程的艺术:从入门到精通####
【10月更文挑战第21天】 本文将深入探讨Java多线程编程的核心概念,通过生动实例和实用技巧,引导读者从基础认知迈向高效并发编程的殿堂。我们将一起揭开线程管理的神秘面纱,掌握同步机制的精髓,并学习如何在实际项目中灵活运用这些知识,以提升应用性能与响应速度。 ####
37 3
|
14天前
|
Java
Java中的多线程编程:从入门到精通
本文将带你深入了解Java中的多线程编程。我们将从基础概念开始,逐步深入探讨线程的创建、启动、同步和通信等关键知识点。通过阅读本文,你将能够掌握Java多线程编程的基本技能,为进一步学习和应用打下坚实的基础。
|
15天前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
39 4
|
1月前
|
开发框架 IDE Java
java制作游戏,如何使用libgdx,入门级别教学
本文是一篇入门级教程,介绍了如何使用libgdx游戏开发框架创建一个简单的游戏项目,包括访问libgdx官网、设置项目、下载项目生成工具,并在IDE中运行生成的项目。
44 1
java制作游戏,如何使用libgdx,入门级别教学