目录
- 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);//[b, c]
- new Thread(()->{
- System.out.println(Thread.currentThread().getName() + "读取set:" + set);//[c]
- try
- {
- TimeUnit.SECONDS.sleep(2);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "再次读取set:" + set);//[c]
- }).start();
- new Thread(()->{
- System.out.println(Thread.currentThread().getName() + "读取set:" + set);//[c]
- try
- {
- TimeUnit.SECONDS.sleep(2);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "再次读取set:" + set);//[c]
- }).start();
- try
- {
- TimeUnit.SECONDS.sleep(1);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- set.remove("b");
- System.out.println(Thread.currentThread().getName() + "读取修改后的set:" + set);//[c]
- }
- }
复制代码 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[i] == null)
- return i;
- //object不为null
- } else {
- for (int i = index; i < fence; i++)
- if (o.equals(elements[i]))
- 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[i] != snapshot[i] && eq(e, current[i]))
- return false;
- //从改变后的数组右边查看是否存在要添加的元素
- if (indexOf(e, current, common, len) >= 0)
- return false;
- }
- //复制原数组并扩容,把e加入到数组的末尾,set回array
- Object[] newElements = Arrays.copyOf(current, len + 1);
- newElements[len] = 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[i] == null)
- return i;
- //object不为null
- } else {
- for (int i = index; i < fence; i++)
- if (o.equals(elements[i]))
- return i;
- }
- return -1;
- }
复制代码 3.4. 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[i] == null)
- return i;
- //object不为null
- } else {
- for (int i = index; i < fence; i++)
- if (o.equals(elements[i]))
- return i;
- }
- return -1;
- }
复制代码 3.4.1.2. 存在的话再去删除
参考10.CopyOnWriteArrayList.md remove方法
4. 总结
底层直接通过调用CopyOnWriteArrayList实现的,因此有序
5. 参考
- [學習筆記-Java集合-12] Set - CopyOnWriteArraySet源碼分析 - 台部落
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |