标签:
注:在看这篇文章之前,如果对ArrayList底层不清楚的话,建议先去看看ArrayList源码解析。
http://www.cnblogs.com/java-zhao/p/5102342.html
1、对于CopyOnWriteArrayList需要掌握以下几点
注:CopyOnWriteArrayList是一个线程安全,读操作时无锁的ArrayList。
2、创建
public CopyOnWriteArrayList()
使用方法:
List<String> list = new CopyOnWriteArrayList<String>();
相关源代码:
private volatile transient Object[] array;//底层数据结构 /** * 获取array */ final Object[] getArray() { return array; } /** * 设置Object[] */ final void setArray(Object[] a) { array = a; } /** * 创建一个CopyOnWriteArrayList * 注意:创建了一个0个元素的数组 */ public CopyOnWriteArrayList() { setArray(new Object[0]); }
注意点:
3、添加元素
public boolean add(E e)
使用方法:
list.add("hello");
源代码:
/** * 在数组末尾添加元素 * 1)获取锁 * 2)上锁 * 3)获取旧数组及其长度 * 4)创建新数组,容量为旧数组长度+1,将旧数组拷贝到新数组 * 5)将要增加的元素加入到新数组的末尾,设置全局array为新数组 */ public boolean add(E e) { final ReentrantLock lock = this.lock;//这里为什么不直接用this.lock(即类中已经初始化好的锁)去上锁 lock.lock();//上锁 try { Object[] elements = getArray();//获取当前的数组 int len = elements.length;//获取当前数组元素 /* * Arrays.copyOf(elements, len + 1)的大致执行流程: * 1)创建新数组,容量为len+1, * 2)将旧数组elements拷贝到新数组, * 3)返回新数组 */ Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e;//新数组的末尾元素设成e setArray(newElements);//设置全局array为新数组 return true; } finally { lock.unlock();//解锁 } }
注意点:
疑问:
4、获取元素
public E get(int index)
使用方法:
list.get(0)
源代码:
/** * 根据下标获取元素 * 1)获取数组array * 2)根据索引获取元素 */ public E get(int index) { return (E) (getArray()[index]); }
注意点:
疑问:读操作会发生脏读,为什么?
5、删除元素
public boolean remove(Object o)
使用方法:
list.remove("hello")
源代码:
/** * 删除list中的第一个o * 1)获取锁、上锁 * 2)获取旧数组、旧数组的长度len * 3)如果旧数组长度为0,返回false * 4)如果旧数组有值,创建新数组,容量为len-1 * 5)从0开始遍历数组中除了最后一个元素的所有元素 * 5.1)将旧数组中将被删除元素之前的元素复制到新数组中, * 5.2)将旧数组中将被删除元素之后的元素复制到新数组中 * 5.3)将新数组赋给全局array * 6)如果是旧数组的最后一个元素要被删除,则 * 6.1)将旧数组中将被删除元素之前的元素复制到新数组中 * 6.2)将新数组赋给全局array */ public boolean remove(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray();//获取原数组 int len = elements.length;//获取原数组长度 if (len != 0) {//如果有数据 // Copy while searching for element to remove // This wins in the normal case of element being present int newlen = len - 1;//新数组长度为原数组长度-1 Object[] newElements = new Object[newlen];//创建新数组 for (int i = 0; i < newlen; ++i) {//遍历新数组(不包含最后一个元素) if (eq(o, elements[i])) { // 将旧数组中将被删除元素之后的元素复制到新数组中 for (int k = i + 1; k < len; ++k) newElements[k - 1] = elements[k]; setArray(newElements);//将新数组赋给全局array return true; } else newElements[i] = elements[i];//将旧数组中将被删除元素之前的元素复制到新数组中 } if (eq(o, elements[newlen])) {//将要删除的元素时旧数组中的最后一个元素 setArray(newElements); return true; } } return false; } finally { lock.unlock(); } }
判断两个对象是否相等:
/** * 判断o1与o2是否相等 */ private static boolean eq(Object o1, Object o2) { return (o1 == null ? o2 == null : o1.equals(o2)); }
注意点:
6、遍历所有元素
iterator() hasNext() next()
使用方法:
讲解用的:
Iterator<String> itr = list.iterator(); while(itr.hasNext()){ System.out.println(itr.next()); }
实际中使用的:
for(String str : list){ System.out.println(str); }
源代码:
public Iterator<E> iterator() { return new COWIterator<E>(getArray(), 0); }
private static class COWIterator<E> implements ListIterator<E> { private final Object[] snapshot;//数组快照 private int cursor;//可看做数组索引 private COWIterator(Object[] elements, int initialCursor) { cursor = initialCursor; snapshot = elements;//将实际数组赋给数组快照 } public boolean hasNext() { return cursor < snapshot.length;//0~snapshot.length-1 } public E next() { if (!hasNext()) throw new NoSuchElementException(); return (E) snapshot[cursor++]; }
说明:这一块儿代码非常简单,看看代码注释就好。
注意:
由于遍历的只是全局数组的一个副本,即使全局数组发生了增删改变化,副本也不会变化,所以不会发生并发异常。但是,可能在遍历的过程中读到一些刚刚被删除的对象。
注意点:
总结:
疑问:
标签:
原文地址:http://www.cnblogs.com/java-zhao/p/5121944.html