关于 CopyOnWriteArrayList remove(Object o)方法的疑问记录
源码如下
1 /** 2 * Removes the first occurrence of the specified element from this list, 3 * if it is present. If this list does not contain the element, it is 4 * unchanged. More formally, removes the element with the lowest index 5 * {@code i} such that 6 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 7 * (if such an element exists). Returns {@code true} if this list 8 * contained the specified element (or equivalently, if this list 9 * changed as a result of the call). 10 * 11 * @param o element to be removed from this list, if present 12 * @return {@code true} if this list contained the specified element 13 */ 14 public boolean remove(Object o) { 15 //保存数组快照 16 Object[] snapshot = getArray(); 17 //获得要查找对象的索引 18 //这个步骤无锁,是为了减小锁的粒度,提高并发度 19 int index = indexOf(o, snapshot, 0, snapshot.length); 20 //根据索引,从数组移除对象 21 return (index < 0) ? false : remove(o, snapshot, index); 22 } 23 24 /** 25 * static version of indexOf, to allow repeated calls without 26 * needing to re-acquire array each time. 27 * @param o element to search for 28 * @param elements the array 29 * @param index first index to search 30 * @param fence one past last index to search 31 * @return index of element, or -1 if absent 32 */ 33 private static int indexOf(Object o, Object[] elements, 34 int index, int fence) { 35 if (o == null) { 36 for (int i = index; i < fence; i++) 37 if (elements[i] == null) 38 return i; 39 } else { 40 for (int i = index; i < fence; i++) 41 if (o.equals(elements[i])) 42 return i; 43 } 44 return -1; 45 } 46 47 /** 48 * A version of remove(Object) using the strong hint that given 49 * recent snapshot contains o at the given index. 50 */ 51 private boolean remove(Object o, Object[] snapshot, int index) { 52 //进入这个方法有个默认条件,snapshot[index] == o 53 //而这里要考虑多线程的情况,即原有的数组可能已经被其他线程修改了,snapshot已经是过时的数据 54 final ReentrantLock lock = this.lock; 55 lock.lock(); 56 try { 57 //获取最新数组数据 58 Object[] current = getArray(); 59 int len = current.length; 60 if (snapshot != current) findIndex: { 61 //考虑数组数据已经被其他线程修改了的情况,要重新定位index值 62 int prefix = Math.min(index, len); 63 //遍历数组,从0到min(index, len),查找o的index 64 for (int i = 0; i < prefix; i++) { 65 if (current[i] != snapshot[i] && eq(o, current[i])) { 66 index = i; 67 break findIndex; 68 } 69 } 70 if (index >= len) 71 return false; 72 if (current[index] == o) 73 break findIndex; 74 index = indexOf(o, current, index, len); 75 if (index < 0) 76 return false; 77 } 78 79 //实际的删除操作 80 Object[] newElements = new Object[len - 1]; 81 System.arraycopy(current, 0, newElements, 0, index); 82 System.arraycopy(current, index + 1, 83 newElements, index, 84 len - index - 1); 85 //用新数组替换旧数据 86 setArray(newElements); 87 return true; 88 } finally { 89 lock.unlock(); 90 } 91 }
不明白的地方在于从60行开始,到77行为止,也就是findIndex 这个功能。
其进入条件是快照数组和当前数组不相等,即其他线程对数组进行了修改的操作,所以需要重新查找index值。在我理解,只需要三行代码就可以解决了,如下:
index = indexOf(o, current, 0, len);
if (index < 0)
return false;
这个方法是内部实现好的,直接调用饥渴获取到current,即新数组的o对象对应的index值。
而源码的那种实现我就不太懂了。尤其是循环里面的逻辑:
if (current[i] != snapshot[i] && eq(o, current[i]))
这个判断是处于什么考虑,想破脑袋还是不明白。先记录下来。
TODO