天天看點

講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

0 前言

我們知道 ArrayList 非線程安全,需要自己加鎖或者使用

Collections.synchronizedList

包裝.

從JDK1.5開始JUC裡提供了使用 CopyOnWrite 機制實作的并發容器線程安全的 List - CopyOnWriteArrayList,簡稱 COW

1 CopyOnWrite 設計思想

1.1 基本概念

CopyOnWrite 寫時複制.

一般來說就是當我們往一個容器添加元素的時候,不直接往目前容器添加,而是先将目前容器複制出一個新的容器,往新的容器裡添加元素,添加完元素之後,再将原容器引用指向新容器.

即一開始大家都在共享同一内容,當有人想修改該内容時,才會真地把内容copy出去形成一個新的内容然後再改,這是一種延時懶惰政策.

1.2 設計優點

可并發讀 CopyOnWrite 容器,而無需加鎖,因為目前容器不會添加任何元素.

是以這也是一種讀寫分離的思想,讀寫的是不同的容器.

2 繼承體系

  • 和 ArrayList 的繼承體系類似
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

3 屬性

  • 保護所有更改器的鎖
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)
  • 僅能通過getArray / setArray通路的數組
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)
  • lock 記憶體偏移量
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

4 構造方法

4.1 無參

  • 建立一個空 list
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

4.2 有參

  • 建立一個清單,該清單包含指定集合的元素,其順序由集合的疊代器傳回。
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)
  • 建立一個儲存給定數組副本的清單
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)
  • 下面開始看源碼,到底是如何實作寫時複制的.

5 add(E e)

向 COW 裡添加元素,是需要加鎖的,否則并發寫時 copy 出N個副本!

講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

getArray

  • 擷取數組.非priavte,以便也可以從CopyOnWriteArraySet類(直接組合了CopyOnWriteArrayList作為成員變量)通路
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

setArray

  • 将引用設定到新數組
  • 講完CopyOnWriteArrayList源碼,面試官當場給我發了offer(上)0 前言1 CopyOnWrite 設計思想2 繼承體系3 屬性4 構造方法5 add(E e)

都加鎖,為什麼還需要拷貝數組,而不直接在原數組修改?

  • volatile 修飾的是數組引用!簡單的在原來數組修改幾個元素的值,這種操作是無法發揮可見性的,必須通過修改數組記憶體位址
  • 在新數組上執行 copyOf,對原數組無任何影響,隻有新數組完全拷貝完成之後,外部才能通路,避免了原數組資料變動可能造成的不良影響

繼續閱讀