CopyOnWrite容器解決的併發問題
先看這麼一段代碼: public static void main(String[] args) throws InterruptedException {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
final ArrayList<String> list = new ArrayList<String>(
a);
Thread t = new Thread(new Runnable() {
int count = -1;
@Override
public void run() {
while (true) {
list.add(count++ + "");
}
}
});
t.setDaemon(true);
t.start();
Thread.currentThread().sleep(3);
for (String s : list) {
System.out.println(s);
}
}
首先一個線程對ArrayList進行遍歷操作,此間“休息”一段時間,另外一個線程進來,對List進行加入操作,此時“休息”後的線程繼續對list遍歷操作,運行爆出以下異常:
這就是ArrayList在併發狀態下發生錯誤,如何解決呢?引出今日豬腳--CopyOnWrite容器。
一、源碼
- put方法:
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
該方法對put操作上鎖,並複製了原數組對象,對複製出來的數據進行修改操作,並在最後讓原引用指向新對象,如此一來,就解決了併發問題。