java之CopyOnWriteArraySet源码分析
- 2019 年 11 月 5 日
- 笔记
CopyOnWriteArraySet的源码分析,当自己整理了一下源码流程时发现这篇文章没什么写头,底层是在基于利用CopyOnWriteArrayList。
但是这篇文章既然开始了,也不能草草了事,我们还是继续分享上篇文章没有提到的内容好了,下面我们开始我们的示例程序代码咯。
package com.wpw.asyncthreadpool; import java.util.concurrent.CopyOnWriteArraySet; public class CopyOnWriteArraySetTest { public static void main(String[] args) { CopyOnWriteArraySet<String> copyOnWriteArraySet=new CopyOnWriteArraySet<>(); boolean flag = copyOnWriteArraySet.add("abcd"); System.out.println("flag = " + flag); System.out.println("copyOnWriteArraySet = " + copyOnWriteArraySet); copyOnWriteArraySet.clear(); boolean contains = copyOnWriteArraySet.contains("abcd"); System.out.println("contains = " + contains); } }
上面仅仅是自己写的一点示例程序,下面我们分享下equals()方法的源码。
public static void main(String[] args) { CopyOnWriteArraySet<String> copyOnWriteArraySet=new CopyOnWriteArraySet<>(); boolean flag = copyOnWriteArraySet.add("abcd"); CopyOnWriteArraySet<String> copyOnWriteArraySet1=new CopyOnWriteArraySet<>(); copyOnWriteArraySet1.add("abcd"); boolean equals = copyOnWriteArraySet.equals(copyOnWriteArraySet1); System.out.println("equals = " + equals);//equals=true }
上面我自己手动new了两个集合对象,分别对其进行添加元素。然后调用equals方法进行判断,输出的结果信息已在代码注释说明。接下来我们看下是如何判断的。
public boolean equals(Object o) { if (o == this)//首先判断当前对象与传入额对象的地址是否相等,相等返回true return true; if (!(o instanceof Set)) //判断对象o是否是set类型,不是直接返回false就可以了,没有必要在进行判断 return false; Set<?> set = (Set<?>)(o);//将传入的对象强制转换为Set接口类型 Iterator<?> it = set.iterator();//获取当前set集合的迭代器 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; }
上面针对两个set集合,必须满足两个集合里面的每个元素必须相等才相等,否则不相等。
我们看下在CopyOnWriteArrayList源码里面我们没有介绍到的containsAll()方法,由于这篇讲的是set,但是底层还是使用的是CopyOnWriteArrayList,所以我们这里继续分析。
public boolean containsAll(Collection<?> c) { Object[] elements = getArray();//获取当前集合列表 int len = elements.length;//长度 for (Object e : c) {//循环遍历传入集合的每个集合元素,调用indexOf方法进行判断,如果不包含直接返回false if (indexOf(e, elements, 0, len) < 0) return false; } return true; }
ok,关于上面的conatinsAll方法我们已经走完了整个流程,由于还是调用的indexOf方法,这个方法在上篇文章已经分析过了,需要的可以先看上面的那篇文章。
在项目中大部分我们都是用集合进行操作,有时集合转为数组还是很常见的操作,下面我们继续介绍下toArray()这个方法。
public Object[] toArray() { return al.toArray(); //这里的a1就是private final CopyOnWriteArrayList<E> al;集合的引用 }
我们继续看是如何一步一步调用的toArray()方法。
public Object[] toArray() { Object[] elements = getArray(); return Arrays.copyOf(elements, elements.length); }
public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); }
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") //首先判断是否是Objectp[]类型,不是通过调用底层方法实现 //是的话直接创建一个长度为newLength长度的Object[]数组 T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); //下面就是调用System.arraycopy方法进行拷贝了 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
好了,这里主要介绍下最后一个方法的实现了,因为上面都是在层层调用方法。
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
我们看上面的方法修饰符是由native关键字修饰的,所以它是在本地方法栈执行的,不是在java栈执行的,需要了解的可以看下我的公众号历史信息关于虚拟机的内容。
到这里我们的分享内容就结束了,今天写了CopyOnWriteArrayList的姊妹篇
CopyOnWriteArraySet的源码分析,其实底层实现是基于CopyOnWriteArrayList的,喜欢文章的可以关注公众号,转发分享一下。