您好,登錄后才能下訂單哦!
這篇文章主要介紹java中COW機(jī)制已經(jīng)相關(guān)類是什么,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!
COW機(jī)制已經(jīng)相關(guān)類
Vector和SynchronizedList
我們知道ArrayList是用于替代Vector的,Vector是線程安全的容器。因為它幾乎在每個方法聲明處都加了synchronized關(guān)鍵字來使容器安全。如果使用Collections.synchronizedList(new ArrayList())來使ArrayList變成是線程安全的話,也是幾乎都是每個方法都加上synchronized關(guān)鍵字的,只不過它不是加在方法的聲明處,而是方法的內(nèi)部。
多線程下for循環(huán)迭代Vector或者SynchronizedList,進(jìn)行delete和get操作會發(fā)生數(shù)組下標(biāo)錯誤的異常。
在JDK5以后,Java推薦使用for-each(迭代器)來遍歷我們的集合,好處就是簡潔、數(shù)組索引的邊界值只計算一次。如果使用for-each(迭代器)來做上面的操作,會拋出ConcurrentModificationException異常。
如果想要完美解決上面所講的問題,我們可以在遍歷前加鎖:
遍歷一下容器都要我加上鎖,這這這不是要慢死了嗎。的確是挺慢的。因為加鎖粒度太大。
CopyOnWriteArrayList是同步List的替代品,CopyOnWriteArraySet是同步Set的替代品。
Hashtable、Vector加鎖的粒度大(直接在方法聲明處使用synchronized)ConcurrentHashMap、CopyOnWriteArrayList加鎖粒度小(用各種的方式來實現(xiàn)線程安全,比如我們知道的ConcurrentHashMap用了cas鎖、volatile等方式來實現(xiàn)線程安全..)JUC下的線程安全容器在遍歷的時候不會拋出ConcurrentModificationException異常所以一般來說,我們都會使用JUC包下給我們提供的線程安全容器,而不是使用老一代的線程安全容器。
CopyOnWriteArrayList實現(xiàn)原理
CopyOnWriteArrayList是線程安全容器(相對于ArrayList),底層通過復(fù)制數(shù)組的方式來實現(xiàn)。CopyOnWriteArrayList在遍歷的使用不會拋出ConcurrentModificationException異常,并且遍歷的時候就不用額外加鎖元素可以為null
/** 可重入鎖對象 */ final transient ReentrantLock lock = new ReentrantLock(); /** CopyOnWriteArrayList底層由數(shù)組實現(xiàn),volatile修飾 */ private transient volatile Object[] array; final Object[] getArray() { return array; } final void setArray(Object[] a) { array = a; } // 初始化CopyOnWriteArrayList相當(dāng)于初始化數(shù)組 public CopyOnWriteArrayList() { setArray(new Object[0]); }
CopyOnWriteArrayList底層就是數(shù)組,加鎖就交由ReentrantLock來完成。
通過代碼我們可以知道:在add(),set(),remove() 的時候就上鎖,并復(fù)制一個新數(shù)組,增加操作在新數(shù)組上完成,將array指向到新數(shù)組中,最后解鎖。在修改時,復(fù)制出一個新數(shù)組,修改的操作在新數(shù)組中完成,最后將新數(shù)組交由array變量指向。寫加鎖,讀不加鎖
CopyOnWriteArrayList缺點
內(nèi)存占用:如果CopyOnWriteArrayList經(jīng)常要增刪改里面的數(shù)據(jù),經(jīng)常要執(zhí)行add()、set()、remove()的話,那是比較耗費內(nèi)存的。
因為我們知道每次add()、set()、remove()這些增刪改操作都要復(fù)制一個數(shù)組出來。
數(shù)據(jù)一致性:CopyOnWrite容器只能保證數(shù)據(jù)的最終一致性,不能保證數(shù)據(jù)的實時一致性。
從上面的例子也可以看出來,比如線程A在迭代CopyOnWriteArrayList容器的數(shù)據(jù)。線程B在線程A迭代的間隙中將CopyOnWriteArrayList部分的數(shù)據(jù)修改了(已經(jīng)調(diào)用setArray()了)。但是線程A迭代出來的是原有的數(shù)據(jù)。
以上是java中COW機(jī)制已經(jīng)相關(guān)類是什么的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。