【从入门到放弃-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,转载请注明出处

目录
相关文章
|
29天前
|
安全 Java 程序员
深入理解Java内存模型与并发编程####
本文旨在探讨Java内存模型(JMM)的复杂性及其对并发编程的影响,不同于传统的摘要形式,本文将以一个实际案例为引子,逐步揭示JMM的核心概念,包括原子性、可见性、有序性,以及这些特性在多线程环境下的具体表现。通过对比分析不同并发工具类的应用,如synchronized、volatile关键字、Lock接口及其实现等,本文将展示如何在实践中有效利用JMM来设计高效且安全的并发程序。最后,还将简要介绍Java 8及更高版本中引入的新特性,如StampedLock,以及它们如何进一步优化多线程编程模型。 ####
31 0
|
3月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第17天】本文详细介绍了Java编程中Map的使用,涵盖Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的并发处理和性能优化技巧,适合初学者和进阶者学习。
76 3
|
2天前
|
自然语言处理 Java
Java中的字符集编码入门-增补字符(转载)
本文探讨Java对Unicode的支持及其发展历程。文章详细解析了Unicode字符集的结构,包括基本多语言面(BMP)和增补字符的表示方法,以及UTF-16编码中surrogate pair的使用。同时介绍了代码点和代码单元的概念,并解释了UTF-8的编码规则及其兼容性。
74 60
|
1月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
58 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
29天前
|
监控 架构师 Java
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
|
2月前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
157 6
|
2月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
2月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
2月前
|
存储 缓存 安全
Java内存模型(JMM):深入理解并发编程的基石####
【10月更文挑战第29天】 本文作为一篇技术性文章,旨在深入探讨Java内存模型(JMM)的核心概念、工作原理及其在并发编程中的应用。我们将从JMM的基本定义出发,逐步剖析其如何通过happens-before原则、volatile关键字、synchronized关键字等机制,解决多线程环境下的数据可见性、原子性和有序性问题。不同于常规摘要的简述方式,本摘要将直接概述文章的核心内容,为读者提供一个清晰的学习路径。 ####
47 2
|
2月前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
86 5