找回密码
 立即注册
首页 业界区 业界 Java源码分析系列笔记-11.CopyOnWriteArraySet

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

坡琨 2025-9-25 20:54:24
目录

  • 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. 如何使用
  1. public class CopyOnWriteArraySetTest
  2. {
  3.     public static void main(String[] args)
  4.     {
  5.         CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
  6.         set.add("a");
  7.         set.add("b");
  8.         set.add("c");
  9.         set.remove("a");
  10.         System.out.println(set.contains("a"));//false
  11.         System.out.println(Thread.currentThread().getName() + "读取set:" + set);//[b, c]
  12.         new Thread(()->{
  13.             System.out.println(Thread.currentThread().getName() + "读取set:" + set);//[c]
  14.             try
  15.             {
  16.                 TimeUnit.SECONDS.sleep(2);
  17.             }
  18.             catch (InterruptedException e)
  19.             {
  20.                 e.printStackTrace();
  21.             }
  22.             System.out.println(Thread.currentThread().getName() + "再次读取set:" + set);//[c]
  23.         }).start();
  24.         new Thread(()->{
  25.             System.out.println(Thread.currentThread().getName() + "读取set:" + set);//[c]
  26.             try
  27.             {
  28.                 TimeUnit.SECONDS.sleep(2);
  29.             }
  30.             catch (InterruptedException e)
  31.             {
  32.                 e.printStackTrace();
  33.             }
  34.             System.out.println(Thread.currentThread().getName() + "再次读取set:" + set);//[c]
  35.         }).start();
  36.         try
  37.         {
  38.             TimeUnit.SECONDS.sleep(1);
  39.         }
  40.         catch (InterruptedException e)
  41.         {
  42.             e.printStackTrace();
  43.         }
  44.         set.remove("b");
  45.         System.out.println(Thread.currentThread().getName() + "读取修改后的set:" + set);//[c]
  46.     }
  47. }
复制代码
3. 原理分析

3.1. 构造方法

3.1.1. 底层使用CopyOnWriteArrayList实现
  1. public class CopyOnWriteArraySet<E> extends AbstractSet<E>
  2.         implements java.io.Serializable {
  3.     //底层使用的是CopyOnWriteArrayList实现
  4.     private final CopyOnWriteArrayList<E> al;
  5.    
  6.         public CopyOnWriteArraySet() {
  7.                 //默认一个元素的数组
  8.                 al = new CopyOnWriteArrayList<E>();
  9.         }
  10. }
复制代码
3.2. add方法
  1. public boolean add(E e) {
  2.         //调用CopyOnWriteArrayList addIfAbsent方法
  3.     return al.addIfAbsent(e);
  4. }
复制代码
3.2.1. 转调CopyOnWriteArrayList addIfAbsent


  • CopyOnWriteArrayList addIfAbsent
  1. public boolean addIfAbsent(E e) {
  2.         //获取原数组
  3.     Object[] snapshot = getArray();
  4.     //如果在数组中已经存在,那么返回false
  5.     return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
  6.             //元素还不在数组中,则加入
  7.         addIfAbsent(e, snapshot);
  8. }
复制代码

  • 3行:获取原数组
  • 5行:遍历数组是否存在该object
  • 7行:不在的话插入list尾部
下面分别说明:
3.2.1.1. 遍历数组是否存在该object
  1. private static int indexOf(Object o, Object[] elements,
  2.                            int index, int fence) {
  3.     //object为null
  4.     if (o == null) {
  5.         for (int i = index; i < fence; i++)
  6.             if (elements[i] == null)
  7.                 return i;
  8.     //object不为null
  9.     } else {
  10.         for (int i = index; i < fence; i++)
  11.             if (o.equals(elements[i]))
  12.                 return i;
  13.     }
  14.     return -1;
  15. }
复制代码
3.2.1.2. 不在的话则加锁插入list尾部


  • CopyOnWriteArrayList addIfAbsent
  1. //把e加入到snapshot数组中
  2. private boolean addIfAbsent(E e, Object[] snapshot) {
  3.     final ReentrantLock lock = this.lock;
  4.     lock.lock();
  5.     try {
  6.         Object[] current = getArray();
  7.         int len = current.length;
  8.         //原数组跟现在的数组不一样了           
  9.         if (snapshot != current) {
  10.             // Optimize for lost race to another addXXX operation
  11.             int common = Math.min(snapshot.length, len);
  12.             //遍历改变后的数组左边
  13.             for (int i = 0; i < common; i++)
  14.                     //有一个位置不相同 且 改变后的数组这个位置xx的元素与要添加的元素相同,说明已经存在,返回false
  15.                 if (current[i] != snapshot[i] && eq(e, current[i]))
  16.                     return false;
  17.             //从改变后的数组右边查看是否存在要添加的元素
  18.             if (indexOf(e, current, common, len) >= 0)
  19.                     return false;
  20.         }
  21.         //复制原数组并扩容,把e加入到数组的末尾,set回array
  22.         Object[] newElements = Arrays.copyOf(current, len + 1);
  23.         newElements[len] = e;
  24.         setArray(newElements);
  25.         return true;
  26.     } finally {
  27.         lock.unlock();
  28.     }
  29. }
复制代码
大体逻辑跟10.CopyOnWriteArrayList.md的remove方法差不多
3.3. contains方法
  1. public boolean contains(Object o) {
  2.         //转调CopyOnWriteArrayList的contains方法
  3.     return al.contains(o);
  4. }   
复制代码
3.3.1. 转调CopyOnWriteArrayList的contains


  • CopyOnWriteArrayList的contains
  1. //CopyOnWriteArrayList的contains方法
  2. public boolean contains(Object o) {
  3.     Object[] elements = getArray();
  4.     //遍历数组查找
  5.     return indexOf(o, elements, 0, elements.length) >= 0;
  6. }
复制代码
3.3.1.1. 遍历数组判断是否存在该object
  1. private static int indexOf(Object o, Object[] elements,
  2.                            int index, int fence) {
  3.     //object为null
  4.     if (o == null) {
  5.         for (int i = index; i < fence; i++)
  6.             if (elements[i] == null)
  7.                 return i;
  8.     //object不为null
  9.     } else {
  10.         for (int i = index; i < fence; i++)
  11.             if (o.equals(elements[i]))
  12.                 return i;
  13.     }
  14.     return -1;
  15. }
复制代码
3.4. remove方法


  • remove
  1. public boolean remove(Object o) {
  2.         //转调CopyOnWriteArrayList的remove方法
  3.     return al.remove(o);
  4. }
复制代码
3.4.1. 转调CopyOnWriteArrayList的remove方法


  • CopyOnWriteArrayList remove
  1. //CopyOnWriteArrayList的remove方法
  2. public boolean remove(Object o) {
  3.     Object[] snapshot = getArray();
  4.     int index = indexOf(o, snapshot, 0, snapshot.length);
  5.     return (index < 0) ? false : remove(o, snapshot, index);
  6. }
复制代码

  • 3行:获取原数组
  • 4行:遍历数组是否存在该object
  • 5行:存在的话调用CopyOnWriteArrayList的remove方法删除
3.4.1.1. 遍历底层数组判断是否存在该object
  1. private static int indexOf(Object o, Object[] elements,
  2.                            int index, int fence) {
  3.     //object为null
  4.     if (o == null) {
  5.         for (int i = index; i < fence; i++)
  6.             if (elements[i] == null)
  7.                 return i;
  8.     //object不为null
  9.     } else {
  10.         for (int i = index; i < fence; i++)
  11.             if (o.equals(elements[i]))
  12.                 return i;
  13.     }
  14.     return -1;
  15. }
复制代码
3.4.1.2. 存在的话再去删除

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

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


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

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册