关于 CopyOnWriteArrayList remove(Object o)方法的疑问记录

Posted zhangxuezhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于 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&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;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

 

以上是关于关于 CopyOnWriteArrayList remove(Object o)方法的疑问记录的主要内容,如果未能解决你的问题,请参考以下文章

CopyOnWriteArrayList 的具体介绍

CopyOnWriteArrayList

关于Copy On Write Array List,你会安全使用么

Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList

CopyOnWriteArrayList,CopyOnWriteArraySet源码分析

CopyOnWriteArrayList 源码解读