寫在之前
對於ArrayList的面試題目網上比較多,但是大多數從ArrayList的數據結構出發,比如查找、修改的等效率問題分析,本篇文章想從併發的角度入手,給大家講講ArrayList的併發問題該如何回答。
面試回顧
通常容器之類的問題由於比較基礎,一般在一面考察的比較多,同時這也成爲決定能否進入二面的關鍵因素。
面試官:我看你簡歷上面寫能夠熟練掌握Java基礎知識,平時有使用過哪些容器呢?
我:面試官您好,一般工作中使用的比較多的有ArrayList、LinkedList、HashSet、hashMap等。
面試官:那他們都是線程安全的嗎?
我:不是線程安全的,他們在高併發情況下都會有線程安全問題。
面試官:那你能寫一個程序簡單說說ArrayList會有哪些那問題嗎?
當然這時候肯定得拿出平時好好積累的程序了。
我:
如下:開啓20個線程,每個線程給生成一個隨機數,並且將隨機數添加到 list 容器中
public class ArrayListUnsafe {
public static void main(String[] args) {
List<String> lists = new ArrayList <>();
for (int i = 0; i < 20; i++) {
new Thread(()->{
lists.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(lists);
},String.valueOf(i)).start();
}
}
}
通常情況下,這個程序會報 java.util.ConcurrentModificationException ,這也是高併發情況下常見的錯誤,併發修改異常
面試官:爲什麼會產生這種問題呢?
我:在多線程下,每次往容器中寫數據時,不保證順序,誰搶佔到了容器誰開始寫入數據,因此可能存在覆蓋情況,導致每次執行的結果都不一致。
面試官:有什麼辦法可以避免這種問題嗎?
我:現在jdk提供了多種方式保證 List 的線程安全。
使用傳統的Vector集合類。但是該類在方法上加上Synchronize關鍵字,保證線程安全。但是jdK已經不推薦了,因爲用了重量級加鎖方式,導致執行效率低。
使用工具, Collections.synchronizedList 保證線程安全。比如
List lists = Collections.synchronizedList(new ArrayList <>());
利用寫時複製的集合類。 CopyOnWriteArrayList
能夠說出寫時複製,這是加分項啊,同學們!!
面試官:能夠簡單說說什麼是 CopyOnWriteArrayList 嗎?
我:寫時複製類似於將讀數據和寫數據過程分離開來。比如
A線程和B線程都開始寫數據,A、B每次寫數據之前,都需要拿到一個許可證(類似於鎖),主內存中數據複製到工作內存中,然後再進行修改,修改完畢之後將容器的引用指向新的數據集,然後再允許別的線程修改。
源碼
比如對於寫時複製的 add() 方法, jdk 源碼如下:
public boolean add(E e) {
// 先獲取鎖,也就是前文說的許可證
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
// 將原數組複製一份
Object[] newElements = Arrays.copyOf(elements, len + 1);
// 添加新值
newElements[len] = e;
// 將數組索引指向新數組
setArray(newElements);
return true;
} finally {
// 最後釋放鎖
lock.unlock();
}
}
每次添加元素的時候,先獲取鎖(也就是許可),之後纔去更新元素。
回答到這種程度, ArrayList 的問題已經算是回答的比較好了,如果一面每個問題都能夠回答上是什麼,爲什麼、怎麼做,進入二面必然是水到渠成的事兒了。
面試官:好了,今天的面試就到這裏,請問你下一場面試什麼時候有時間呢,我來安排一下。
哈哈哈,恭喜你,到了這裏面試已經成功拿下了,開心的準備二面吧
我:我這幾天都有時間的,看你們的安排。
總結
關於容器的問題諸多博客都有描述,關於ArrayList的底層數據結構,如果有同學感興趣可以自己搜索,這裏我就不拾人牙慧了。本文主要從線程安全的角度分析ArrayList的面試題目,一般該如何回答。
最後分享多年面試心得。面試中,面對一個問題,大概按照總分的邏輯回答即可。先直接拋出結論,然後舉例論證自己的結論。一定要第一時間抓住面試官的心裏,否則容易給人抓不着重點或者不着邊際的印象。