欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的CopyOnWriteArrayList原理詳解

 更新時間:2023年12月27日 10:58:10   作者:笑我歸無處  
這篇文章主要介紹了Java中的CopyOnWriteArrayList原理詳解,如源碼所示,CopyOnWriteArrayList和ArrayList一樣,都在內部維護了一個數(shù)組,操作CopyOnWriteArrayList其實就是在操作內部的數(shù)組,需要的朋友可以參考下

CopyOnWriteArrayList的原理是什么

CopyOnWriteArrayList是線程安全版本的ArrayList。

這里先上一小段源碼

final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
/**
 * Gets the array.  Non-private so as to also be accessible
 * from CopyOnWriteArraySet class.
 */
final Object[] getArray() {
    return array;
}
/**
 * Sets the array.
 */
final void setArray(Object[] a) {
    array = a;
}
/**
 * Creates an empty list.
 */
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}

如源碼所示,CopyOnWriteArrayList和ArrayList一樣,都在內部維護了一個數(shù)組。操作CopyOnWriteArrayList其實就是在操作內部的數(shù)組。

但關鍵是和ArrayList的不同之處

1) 使用volatile修飾內部數(shù)組

private transient volatile Object[] array;

看這行代碼,使用volatile修飾了內部數(shù)組 volatile關鍵字保證了每次拿到的內部數(shù)組都是最新值。因為volatile關鍵字表示直接去主存中獲取值,因此哪怕別的線程剛修改完內部數(shù)組,也能保證獲取內部數(shù)組時是最新的。

2) 加鎖

提到并發(fā)編程,當然少不了加鎖。

final transient ReentrantLock lock = new ReentrantLock();

CopyOnWriteArrayList每創(chuàng)建一個實例,都會同時創(chuàng)建一個ReentrantLock鎖。 CopyOnWriteArrayList會在增,刪,改操作時添加鎖,而不會在讀操作時加鎖。

3) 使用COW思想操作數(shù)組。

COW即是CopyOnWrite的縮寫。即每次在寫入之前,先獲取源數(shù)據(jù)的拷貝,修改完拷貝后,再保存到源數(shù)據(jù)中。

get操作

private E get(Object[] a, int index) {
    return (E) a[index];
}
public E get(int index) {
    return get(getArray(), index);
}

如源碼所示,get操作沒有加鎖,直接返回數(shù)組中的對象。

set操作

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();
    }
}

大致流程:

  • 加鎖
  • 獲取源數(shù)組
  • 判斷新值和舊值是否相同
  • 不同的話拷貝源數(shù)組,更新值,然后更新源數(shù)組
  • 相同的話,不更新值,然后更新源數(shù)組(數(shù)組內容沒變)
  • 釋放鎖

add操作

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();
    }
}

大致流程:

  • 加鎖
  • 獲取源數(shù)組
  • 復制一個源數(shù)組長度+1的新數(shù)組
  • 在數(shù)組末尾賦值,然后更新源數(shù)組
  • 釋放鎖

remove操作

public E remove(int index) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = get(elemnts, index);
        int numMoved = len - index - 1;
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        else {
            Object[] newElements = new Object[len - 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            setArray(newElements);
        }
        return oldValue;
    } finally {
        lock.unlock();
    }
}

大致流程:

  • 加鎖
  • 獲取源數(shù)組
  • 判斷刪除的位置是不是數(shù)組末尾
  • 是末尾的話,復制一個數(shù)組長度減一的數(shù)組,然后更新源數(shù)組
  • 不是末尾的話,做成一個不包含需要刪除的元素的新數(shù)組,然后更新源數(shù)組
  • 釋放鎖

以上操作可以看出, 查操作不加鎖 增刪改操作大致流程都是一樣的,先加鎖,然后復制一份源數(shù)組,操作完后寫入源數(shù)組,釋放鎖。

那么為什么要這么做呢?都已經加鎖了,為什么不能直接操作源數(shù)組呢?不然加鎖是為了什么? 這是我第一次看到這種做法時的疑問。接下來一一解釋。

讀操作為什么不加鎖

當然是為了提高讀操作的效率啦

既然加鎖了為什么不能直接操作源數(shù)組?

因為讀操作沒有加鎖。增刪改操作時,讀操作可以在任何一步時獲取數(shù)組里的值。 如果剛生成一個新數(shù)組,還沒有更新里面的值的情況下就被執(zhí)行了讀操作,就會出現(xiàn)不可預料的情況。

因此為了保證數(shù)據(jù)的最終一致性。只有當數(shù)組完全更新結束后,再刷新源數(shù)組的值,才能保證讀取的要么是舊值,要么是最新值。

既然使用COW就可以保證讀操作不出現(xiàn)異常,那為什么還要加鎖?

加鎖是為了保證和其他寫操作不沖突。

CopyOnWriteArrayList的優(yōu)缺點

優(yōu)點: 在保證線程安全的情況下,可以獲得非常高效的讀操作。 雖然寫操作性能低下,但能保證線程安全。

缺點: 因為每次寫操作都需要復制一份新數(shù)組,所以寫操作性能低下,尤其是數(shù)組長度很長時,不建議使用CopyOnWriteArrayList。

CopyOnWriteArrayList的應用場景

高并發(fā)場景,多讀取,少寫入。

到此這篇關于Java中的CopyOnWriteArrayList原理詳解的文章就介紹到這了,更多相關CopyOnWriteArrayList原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實現(xiàn)

    SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實現(xiàn)

    這篇文章主要介紹了SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • Spring boot通過AOP防止API重復請求代碼實例

    Spring boot通過AOP防止API重復請求代碼實例

    這篇文章主要介紹了Spring boot通過AOP防止API重復請求代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • Springboot整合PageOffice 實現(xiàn)word在線編輯保存功能

    Springboot整合PageOffice 實現(xiàn)word在線編輯保存功能

    這篇文章主要介紹了Springboot整合PageOffice 實現(xiàn)word在線編輯保存,本文以Samples5 為示例文件結合示例代碼給大家詳細介紹,需要的朋友可以參考下
    2021-08-08
  • 簡單闡述一下Java集合的概要

    簡單闡述一下Java集合的概要

    今天給大家?guī)淼奈恼率顷P于Java的相關知識,文章圍繞著Java集合的概要展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java中invokedynamic字節(jié)碼指令問題

    Java中invokedynamic字節(jié)碼指令問題

    這篇文章主要介紹了Java中invokedynamic字節(jié)碼指令問題,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-04-04
  • java中BigDecimal進行加減乘除的基本用法

    java中BigDecimal進行加減乘除的基本用法

    大家應該對于不需要任何準確計算精度的數(shù)字可以直接使用float或double運算,但是如果需要精確計算的結果,則必須使用BigDecimal類,而且使用BigDecimal類也可以進行大數(shù)的操作。下面這篇文章就給大家介紹介紹關于java中BigDecimal進行加減乘除的基本用法。
    2016-12-12
  • Selenium Webdriver實現(xiàn)截圖功能的示例

    Selenium Webdriver實現(xiàn)截圖功能的示例

    今天小編就為大家分享一篇Selenium Webdriver實現(xiàn)截圖功能的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • java保留小數(shù)的四種實現(xiàn)方法

    java保留小數(shù)的四種實現(xiàn)方法

    這篇文章主要為大家詳細介紹了java保留小數(shù)的四種實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Java分別利用深度優(yōu)先和廣度優(yōu)先求解迷宮路徑

    Java分別利用深度優(yōu)先和廣度優(yōu)先求解迷宮路徑

    這篇文章主要為大家詳細介紹了Java如何利用深度優(yōu)先的非遞歸遍歷方法和廣度優(yōu)先的遍歷方法實現(xiàn)求解迷宮路徑,文中的示例代碼講解詳細,需要的可以參考一下
    2022-08-08
  • java動態(tài)目錄樹的實現(xiàn)示例

    java動態(tài)目錄樹的實現(xiàn)示例

    在開發(fā)過程中,常常需要對目錄結構進行操作和展示,本文主要介紹了java動態(tài)目錄樹的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03

最新評論