坡琨 发表于 2025-9-25 20:54:24

Java源码分析系列笔记-11.CopyOnWriteArraySet

目录

[*]1. 是什么
[*]2. 如何使用
[*]3. 原理分析

[*]3.1. 构造方法

[*]3.1.1. 底层使用CopyOnWriteArrayList实现

[*]3.2. add方法

[*]3.2.1. 转调CopyOnWriteArrayList addIfAbsent

[*]3.2.1.1. 遍历数组是否存在该object
[*]3.2.1.2. 不在的话则加锁插入list尾部


[*]3.3. contains方法

[*]3.3.1. 转调CopyOnWriteArrayList的contains

[*]3.3.1.1. 遍历数组判断是否存在该object


[*]3.4. remove方法

[*]3.4.1. 转调CopyOnWriteArrayList的remove方法

[*]3.4.1.1. 遍历底层数组判断是否存在该object
[*]3.4.1.2. 存在的话再去删除



[*]4. 总结
[*]5. 参考

1. 是什么

写时复制的set,有序不重复,底层使用CopyOnWriteArrayList实现
2. 如何使用

public class CopyOnWriteArraySetTest
{
    public static void main(String[] args)
    {
      CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();

      set.add("a");
      set.add("b");
      set.add("c");

      set.remove("a");
      System.out.println(set.contains("a"));//false


      System.out.println(Thread.currentThread().getName() + "读取set:" + set);//

      new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "读取set:" + set);//
            try
            {
                TimeUnit.SECONDS.sleep(2);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "再次读取set:" + set);//

      }).start();
      new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "读取set:" + set);//
            try
            {
                TimeUnit.SECONDS.sleep(2);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "再次读取set:" + set);//
      }).start();


      try
      {
            TimeUnit.SECONDS.sleep(1);
      }
      catch (InterruptedException e)
      {
            e.printStackTrace();
      }
      set.remove("b");

      System.out.println(Thread.currentThread().getName() + "读取修改后的set:" + set);//

    }
}3. 原理分析

3.1. 构造方法

3.1.1. 底层使用CopyOnWriteArrayList实现

public class CopyOnWriteArraySet<E> extends AbstractSet<E>
      implements java.io.Serializable {
    //底层使用的是CopyOnWriteArrayList实现
    private final CopyOnWriteArrayList<E> al;
   
        public CopyOnWriteArraySet() {
                //默认一个元素的数组
                al = new CopyOnWriteArrayList<E>();
        }
}3.2. add方法

public boolean add(E e) {
        //调用CopyOnWriteArrayList addIfAbsent方法
    return al.addIfAbsent(e);
}3.2.1. 转调CopyOnWriteArrayList addIfAbsent


[*]CopyOnWriteArrayList addIfAbsent
public boolean addIfAbsent(E e) {
        //获取原数组
    Object[] snapshot = getArray();
    //如果在数组中已经存在,那么返回false
    return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
            //元素还不在数组中,则加入
      addIfAbsent(e, snapshot);
}

[*]3行:获取原数组
[*]5行:遍历数组是否存在该object
[*]7行:不在的话插入list尾部
下面分别说明:
3.2.1.1. 遍历数组是否存在该object

private static int indexOf(Object o, Object[] elements,
                           int index, int fence) {
    //object为null
    if (o == null) {
      for (int i = index; i < fence; i++)
            if (elements == null)
                return i;
    //object不为null
    } else {
      for (int i = index; i < fence; i++)
            if (o.equals(elements))
                return i;
    }
    return -1;
}3.2.1.2. 不在的话则加锁插入list尾部


[*]CopyOnWriteArrayList addIfAbsent
//把e加入到snapshot数组中
private boolean addIfAbsent(E e, Object[] snapshot) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
      Object[] current = getArray();
      int len = current.length;
      //原数组跟现在的数组不一样了           
      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++)
                    //有一个位置不相同 且 改变后的数组这个位置xx的元素与要添加的元素相同,说明已经存在,返回false
                if (current != snapshot && eq(e, current))
                  return false;
            //从改变后的数组右边查看是否存在要添加的元素
            if (indexOf(e, current, common, len) >= 0)
                  return false;
      }
      //复制原数组并扩容,把e加入到数组的末尾,set回array
      Object[] newElements = Arrays.copyOf(current, len + 1);
      newElements = e;
      setArray(newElements);
      return true;
    } finally {
      lock.unlock();
    }
}大体逻辑跟10.CopyOnWriteArrayList.md的remove方法差不多
3.3. contains方法

public boolean contains(Object o) {
        //转调CopyOnWriteArrayList的contains方法
    return al.contains(o);
}    3.3.1. 转调CopyOnWriteArrayList的contains


[*]CopyOnWriteArrayList的contains
//CopyOnWriteArrayList的contains方法
public boolean contains(Object o) {
    Object[] elements = getArray();
    //遍历数组查找
    return indexOf(o, elements, 0, elements.length) >= 0;
}3.3.1.1. 遍历数组判断是否存在该object

private static int indexOf(Object o, Object[] elements,
                           int index, int fence) {
    //object为null
    if (o == null) {
      for (int i = index; i < fence; i++)
            if (elements == null)
                return i;
    //object不为null
    } else {
      for (int i = index; i < fence; i++)
            if (o.equals(elements))
                return i;
    }
    return -1;
}3.4. remove方法


[*]remove
public boolean remove(Object o) {
        //转调CopyOnWriteArrayList的remove方法
    return al.remove(o);
}3.4.1. 转调CopyOnWriteArrayList的remove方法


[*]CopyOnWriteArrayList remove
//CopyOnWriteArrayList的remove方法
public boolean remove(Object o) {
    Object[] snapshot = getArray();
    int index = indexOf(o, snapshot, 0, snapshot.length);
    return (index < 0) ? false : remove(o, snapshot, index);
}

[*]3行:获取原数组
[*]4行:遍历数组是否存在该object
[*]5行:存在的话调用CopyOnWriteArrayList的remove方法删除
3.4.1.1. 遍历底层数组判断是否存在该object

private static int indexOf(Object o, Object[] elements,
                           int index, int fence) {
    //object为null
    if (o == null) {
      for (int i = index; i < fence; i++)
            if (elements == null)
                return i;
    //object不为null
    } else {
      for (int i = index; i < fence; i++)
            if (o.equals(elements))
                return i;
    }
    return -1;
}3.4.1.2. 存在的话再去删除

参考10.CopyOnWriteArrayList.md remove方法
4. 总结

底层直接通过调用CopyOnWriteArrayList实现的,因此有序
5. 参考


[*][學習筆記-Java集合-12] Set - CopyOnWriteArraySet源碼分析 - 台部落

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Java源码分析系列笔记-11.CopyOnWriteArraySet