CopyOnWriteArrayList原始碼解析

2022-01-11 23:08:42 字數 3163 閱讀 7424

目錄copyonwritearraylist通過讀寫分離的形式重構arraylist,保證arraylist在迴圈遍歷過程中的讀寫分離性,保證陣列的最終一致性,適用於多讀少寫的情景下。

![copyonwrite繼承體系](

copyonwritearraylist實現了list,serializable,randomaccess,cloneable介面

實現list介面,為提供add,remove,get,set等操作

實現randomacess介面表示該類可自由訪問

和arraylist的繼承相對比發現cowa和其先輩實現的介面基本一致,其中最本質的是collection和list,保證這兩個類能夠在輕易的進行切換(物件導向的多型性)。

//可重入鎖,實現併發控制

final transient reentrantlock lock = new reentrantlock();

/** the array, accessed only via getarray/setarray. */

//儲存原始陣列物件

private transient volatile object array;

lock 實現寫時加鎖的控制

object array儲存需要的資料

主要解析包括以下幾個方法

public copyonwritearraylist(collection extends e> c) 

setarray(elements);

}

兩個方式的拷貝:第一種方式是如果是相同的直接進行引用即可,第二種方式通過重新賦值陣列並且進行陣列元素型別的轉化來實現。

private static boolean eq(object o1, object o2)
用於判斷兩個物件是否相等,元素可能存在null,需要重寫方法不能使用類似與o1.equals(o2)的方式會導致npe。

/** 替換指定index上的元素*/

public e set(int index, e element) else

return oldvalue;

} finally

}

主要流程:

上鎖獲取index上的物件

檢視兩個是否相等

不相等則copy新的陣列

修改新的陣列並修改引用

解鎖set方法為寫方法,需要繼續進行加鎖,實現多個寫之間的一致性。

記錄index上的元素oldvalue,如果兩個位址是不完全一致的就複製原有陣列並進行元素的修改,最後複製回去。

為什麼使用==進行比較而不是eq(a,b)array中實際儲存的是物件陣列,array不同於hash需要使用hashcode和equals函式來進行判斷

public boolean add(e e)  finally 

}

主要流程:

上鎖拷貝長度為len+1的新陣列

進行複製

修改引用

解鎖從add中就能看出陣列的長度變化情況,與arraylist不同的擴容機制,cow的陣列並不含有空餘空間,陣列完全飽和

向指定位置上新增元素的方法

public void add(int index, e element) 

newelements[index] = element;

setarray(newelements);

} finally

}

主要流程:

上鎖確定右側需要移動的元素

需要移動的元素為0

直接進行擴容

需要移動的元素不為0

進行陣列擴容

分左右兩側進行複製

替換位置上的值

解鎖

public boolean addifabsent(e e) 

/** * a version of addifabsent using the strong hint that given

* recent snapshot does not contain e.

*/private boolean addifabsent(e e, object snapshot)

object newelements = arrays.copyof(current, len + 1);

newelements[len] = e;

setarray(newelements);

return true;

} finally

}

主要流程:

其中有很多非常有意思的小細節

第乙個:先進行了無鎖化的查詢,看是否存在元素,當不存在時再新增。而不是直接進行上鎖在判斷元素是否存在

第二個:正是由於上面的無鎖化操作,導致快照和當前陣列可能不一致,但依然利用上了快照資訊,其中有個比較有意思的問題是沒有直接使用indexof進行重新查詢,而是附加了比較查詢,這裡有個很底層的問題就是==!=的比較速度要比indexof中的eq()的速度快得多,加之對於array大部分的操作都是add或者add(index,e),如果index的值較大的話對於效率的提公升會更加高

這裡addifabsent(index,e)需要兩步:確認是否存在和新增,將第一步的查詢不加鎖,而第二步修改進行加鎖,實屬精髓

azkaban web server原始碼解析

azkaban主要用於hadoop相關job任務的排程,但也可以應用任何需要排程管理的任務,可以完全代替crontab。azkaban主要分為web server 任務上傳,管理,排程 executor server 接受web server的排程指令,進行任務執行 1.資料表 projects 工...

JDK LinkedHashMap原始碼解析

今天來分析一下jdk linkedhashmap的源 public class linkedhashmapextends hashmapimplements map可以看到,linkedhashmap繼承自hashmap,並且也實現了map介面,所以linkedhashmap沿用了hashmap的大...

Redux原始碼createStore解讀常用方法

const store createstore reducer,preloadedstate enhancer 直接返回當前currentstate,獲取state值,return state 我覺得應該深轉殖乙個新的物件返回,不然有可能會被外部修改 function getstate consol...