精灵王


  • 首页

  • 文章归档

  • 所有分类

  • 关于我

  • 搜索
设计模式-行为型 设计模式-创建型 设计模式-结构型 设计 系统设计 设计模式之美 分布式 Redis 并发编程 个人成长 周志明的软件架构课 架构 单元测试 LeetCode 工具 位运算 读书笔记 操作系统 MySQL 异步编程 技术方案设计 集合 设计模式 三亚 游玩 转载 Linux 观察者模式 事件 Spring SpringCloud 实战 实战,SpringCloud 源码分析 线程池 同步 锁 线程 线程模型 动态代理 字节码 类加载 垃圾收集器 垃圾回收算法 对象创建 虚拟机内存 内存结构 Java

源码分析:线程安全的集合—CopyOnWriteArraySet

发表于 2021-06-11 | 分类于 Java | 0

简介

CopyOnWriteArraySet是一个基于CopyOnWriteArrayList实现的线程安全的Set集合,所以该Set和CopyOnWriteArrayList拥有完全相似的特性。

  • 线程安全
  • 可变操作(add、remove、set等)代价高,都是通过复制整个数组实现
  • 迭代器不支持可变操作(add、remove、set),要防止遍历期间线程之间的干扰。
  • 最适合集合大小保持较小,读操作大大超过可变操作的场景

结构分析

CopyOnWriteArraySet继承了AbstractSet,所以具有Set集合的功能,内部持有一个CopyOnWriteArrayList实例,作为数据底层的存储。

public class CopyOnWriteArraySet<E> extends AbstractSet<E>
        implements java.io.Serializable {
    private static final long serialVersionUID = 5457747651344034263L;
    // 内部持有CopyOnWriteArrayList实例
    private final CopyOnWriteArrayList<E> al;
    ...
}

方法分析

构造方法

public CopyOnWriteArraySet() {
    al = new CopyOnWriteArrayList<E>();
}
  • 构造方法就很简单了,就是初始化一个CopyOnWriteArrayList。
  • CopyOnWriteArrayList的源码分析见上一篇。

其他方法

public boolean add(E e) {
    return al.addIfAbsent(e);
}
public boolean addAll(Collection<? extends E> c) {
    return al.addAllAbsent(c) > 0;
}
public boolean contains(Object o) {
    return al.contains(o);
}

public void forEach(Consumer<? super E> action) {
    al.forEach(action);
}
public Iterator<E> iterator() {
    return al.iterator();
}
public boolean remove(Object o) {
    return al.remove(o);
}
public void clear() {
    al.clear();
}
public int size() {
    return al.size();
}

其他方法都是调用的CopyOnWriteArrayList的实现,所以没什么好分析的,总的来说功能很简单,就是依赖于CopyOnWriteArrayList的addIfAbsent方法来实现,List本来是允许添加重复的数据的,但是CopyOnWriteArrayList提供了一个addIfAbsent方法来保证没有重复的数据,addIfAbsent 方法的源码分析可以查看上一篇文章CopyOnWriteArrayList的源码分析。

equals方法

public boolean equals(Object o) {
    if (o == this) // 引用相等
        return true;
    if (!(o instanceof Set)) // 比较的对象都不属于Set,没必要比下去了
        return false; 
    Set<?> set = (Set<?>)(o);
    // 拿到迭代器
    Iterator<?> it = set.iterator();

    // Uses O(n^2) algorithm that is only appropriate
    // for small sets, which CopyOnWriteArraySets should be.

    //  Use a single snapshot of underlying array
    // 当前对象的数组,以及数组长度
    Object[] elements = al.getArray();
    int len = elements.length;
    // Mark matched elements to avoid re-checking
    // 初始化一个长度一样的标识数组,用来记录标识另一个数组是否已经被校验过
    boolean[] matched = new boolean[len];
    int k = 0;
    // 一次遍历
    outer: while (it.hasNext()) {
        if (++k > len) // 遍历发现两个集合长度都不一致
            return false;
        Object x = it.next();
        for (int i = 0; i < len; ++i) {
            // 遍历,比较,并记录下来标志位
            if (!matched[i] && eq(x, elements[i])) {
                matched[i] = true;
                continue outer;
            }
        }
        return false; //没匹配到未校验过的目标一致的值
    }
    return k == len; // 遍历完后只需要校验长度是否一致即可
}

总结

  1. CopyOnWriteArraySet主要是基于CopyOnWriteArrayList的addIfAbsent方法实现的。
  2. CopyOnWriteArraySet是线程安全的有序集合。
精 灵 王 wechat
👆🏼欢迎扫码关注微信公众号👆🏼
  • 本文作者: 精 灵 王
  • 本文链接: https://jinglingwang.cn/archives/copyonwritearrayset
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 设计模式-行为型 # 设计模式-创建型 # 设计模式-结构型 # 设计 # 系统设计 # 设计模式之美 # 分布式 # Redis # 并发编程 # 个人成长 # 周志明的软件架构课 # 架构 # 单元测试 # LeetCode # 工具 # 位运算 # 读书笔记 # 操作系统 # MySQL # 异步编程 # 技术方案设计 # 集合 # 设计模式 # 三亚 # 游玩 # 转载 # Linux # 观察者模式 # 事件 # Spring # SpringCloud # 实战 # 实战,SpringCloud # 源码分析 # 线程池 # 同步 # 锁 # 线程 # 线程模型 # 动态代理 # 字节码 # 类加载 # 垃圾收集器 # 垃圾回收算法 # 对象创建 # 虚拟机内存 # 内存结构 # Java
源码分析:线程安全的列表—CopyOnWriteArrayList
用Redis实现一个相对可靠的分布式锁
  • 文章目录
  • 站点概览
精 灵 王

精 灵 王

青春岁月,以此为伴

106 日志
14 分类
48 标签
RSS
Github E-mail
Creative Commons
Links
  • 添加友链说明
© 2023 精 灵 王
渝ICP备2020013371号
0%