關於 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM