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

Java中的拷貝數(shù)組CopyOnWriteArrayList詳解

 更新時(shí)間:2023年12月20日 09:11:18   作者:Brain_L  
這篇文章主要介紹了Java中的拷貝數(shù)組CopyOnWriteArrayList詳解,ArrayList和LinkedList都不是線程安全的,如果需要線程安全的List,可以使用synchronizedList來(lái)生成一個(gè)同步list,但是這個(gè)同步list的方法都是通過(guò)synchronized修飾來(lái)保證同步的,需要的朋友可以參考下

CopyOnWriteArrayList詳解

ArrayList和LinkedList都不是線程安全的,如果需要線程安全的List,可以使用Collections.synchronizedList來(lái)生成一個(gè)同步list,但是這個(gè)同步list的方法都是通過(guò)synchronized修飾來(lái)保證同步的,并發(fā)性能不高。那么如何提高并發(fā)性能呢?比如某些場(chǎng)景下,對(duì)List的讀操作遠(yuǎn)多于寫(xiě)操作,那么CopyOnWriteArrayList就派上用場(chǎng)了。

1、屬性

/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;

lock是用來(lái)在寫(xiě)操作時(shí)加鎖使用的,具體使用下面方法部分再看。

數(shù)組array是CopyOnWriteArrayList的核心部分了,所有的元素都存放在這個(gè)數(shù)組中。為了保證可見(jiàn)性,所以被volatile修飾著。

2、方法

final Object[] getArray() {
    return array;
}
final void setArray(Object[] a) {
    array = a;
}
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}
public CopyOnWriteArrayList(Collection<? extends E> c) {
    Object[] elements;
    if (c.getClass() == CopyOnWriteArrayList.class)
        elements = ((CopyOnWriteArrayList<?>)c).getArray();
    else {
        elements = c.toArray();
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elements.getClass() != Object[].class)
            elements = Arrays.copyOf(elements, elements.length, Object[].class);
    }
    setArray(elements);
}
public CopyOnWriteArrayList(E[] toCopyIn) {
    setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}

三個(gè)構(gòu)造函數(shù)都是為了給array數(shù)組賦值,生成初始數(shù)組。

下面看下它的幾個(gè)關(guān)鍵方法:get、add、remove

private E get(Object[] a, int index) {
    return (E) a[index];
}
/**
 * {@inheritDoc}
 *
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    return get(getArray(), index);
}

get比較簡(jiǎn)單,就是直接取數(shù)組索引處的元素。注意get方法沒(méi)有加鎖。

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    //1、加鎖
    lock.lock();
    try {
        //2、取原數(shù)組
        Object[] elements = getArray();
        int len = elements.length;
        //3、拷貝生成新數(shù)組
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        //4、新元素加到數(shù)組最后一位
        newElements[len] = e;
        //5、數(shù)組替換
        setArray(newElements);
        return true;
    } finally {
        //6、釋放鎖
        lock.unlock();
    }
}

add方法,上來(lái)就先加鎖,然后取出原數(shù)組后拷貝生成了一個(gè)新的數(shù)組,注意,此時(shí)原有的array數(shù)組沒(méi)有變,get訪問(wèn)時(shí)還是跟之前一樣。當(dāng)把新的數(shù)組替換掉array后,由于是volatile修飾的,get訪問(wèn)時(shí)就會(huì)訪問(wèn)添加過(guò)元素的新數(shù)組。這樣就保證了讀寫(xiě)同時(shí)進(jìn)行時(shí),讀不需要加鎖依然不會(huì)有并發(fā)問(wèn)題。最后釋放鎖后,別的寫(xiě)操作獲得鎖,再次進(jìn)行替換操作,這樣保證寫(xiě)操作與寫(xiě)操作之間不會(huì)有并發(fā)問(wèn)題。

public E remove(int index) {
    final ReentrantLock lock = this.lock;
    //1、獲取鎖
    lock.lock();
    try {
        //2、取原數(shù)組
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = get(elements, index);
        int numMoved = len - index - 1;
        //3、如果被刪除元素是數(shù)組最后一位,直接截取len-1的新數(shù)組
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        //4、否則,分段拷貝生成新數(shù)組
        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 {
        //5、釋放鎖
        lock.unlock();
    }
}

remove與add同理,也是先獲取鎖,同時(shí)生成新的數(shù)組之后再把原有的數(shù)組進(jìn)行替換。

3、總結(jié)

  • 所有的元素均存儲(chǔ)到數(shù)組中
  • 寫(xiě)操作(add/set/remove等)會(huì)改變數(shù)組結(jié)構(gòu),采用新生成一個(gè)數(shù)組然后進(jìn)行替換的做法,保證了在此期間原數(shù)組可以正常訪問(wèn)。同時(shí)操作之前需要先獲取鎖,避免寫(xiě)操作之間產(chǎn)生并發(fā)問(wèn)題。
  • 讀操作由于不需要改變數(shù)組結(jié)構(gòu),且寫(xiě)操作時(shí),對(duì)原有的數(shù)組不進(jìn)行修改,此時(shí)仍可正常讀取。寫(xiě)操作將新數(shù)組進(jìn)行替換后,由于數(shù)組被volatile修飾,保證了可見(jiàn)性,此時(shí)也可正正常讀取。所以讀操作不需要加鎖。
  • 因?yàn)槊看螌?xiě)操作都會(huì)帶來(lái)數(shù)組拷貝,所以當(dāng)讀操作遠(yuǎn)大于寫(xiě)操作時(shí),才可考慮使用此容器。

到此這篇關(guān)于Java中的拷貝數(shù)組CopyOnWriteArrayList詳解的文章就介紹到這了,更多相關(guān)CopyOnWriteArrayList詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合redis中的JSON序列化文件夾操作小結(jié)

    SpringBoot整合redis中的JSON序列化文件夾操作小結(jié)

    在我們?nèi)粘5捻?xiàng)目開(kāi)發(fā)中,使用redis作為緩存,來(lái)提高系統(tǒng)訪問(wèn)速度和緩解系統(tǒng)壓力,在使用中遇到幾個(gè)問(wèn)題,本文給大家詳細(xì)總結(jié)下,對(duì)SpringBoot整合redis?JSON序列化相關(guān)知識(shí)感興趣的朋友一起看看吧
    2022-02-02
  • Java中包的概念和用法實(shí)戰(zhàn)案例分析

    Java中包的概念和用法實(shí)戰(zhàn)案例分析

    這篇文章主要介紹了Java中包的概念和用法,結(jié)合具體案例形式分析了java包的概念、原理、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-09-09
  • Java?Spring?事件監(jiān)聽(tīng)詳情解析

    Java?Spring?事件監(jiān)聽(tīng)詳情解析

    這篇文章主要介紹了Java?Spring?事件監(jiān)聽(tīng)詳情解析,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-07-07
  • eclipse創(chuàng)建一個(gè)基于maven的web項(xiàng)目詳細(xì)步驟

    eclipse創(chuàng)建一個(gè)基于maven的web項(xiàng)目詳細(xì)步驟

    開(kāi)始學(xué)習(xí)maven,并用maven創(chuàng)建了第一個(gè)屬于自己的web項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于eclipse創(chuàng)建一個(gè)基于maven的web項(xiàng)目的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • IDEA中Maven依賴包無(wú)法下載或?qū)氲慕鉀Q方案(系統(tǒng)缺失文件導(dǎo)致)

    IDEA中Maven依賴包無(wú)法下載或?qū)氲慕鉀Q方案(系統(tǒng)缺失文件導(dǎo)致)

    在配置Maven環(huán)境時(shí),可能會(huì)遇到各種報(bào)錯(cuò)問(wèn)題,首先確保Maven路徑配置正確,例如使用apache-maven-3.5.0版本,則需要在系統(tǒng)環(huán)境變量的Path中添加其bin目錄路徑,并上移優(yōu)先級(jí),接下來(lái),在Maven的conf目錄下修改settings.xml文件,將鏡像源改為阿里云
    2024-09-09
  • Java 反射機(jī)制知識(shí)詳細(xì)介紹及總結(jié)

    Java 反射機(jī)制知識(shí)詳細(xì)介紹及總結(jié)

    反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制
    2017-01-01
  • Java解決線程的不安全問(wèn)題之volatile關(guān)鍵字詳解

    Java解決線程的不安全問(wèn)題之volatile關(guān)鍵字詳解

    這篇文章主要介紹了Java解決線程的不安全問(wèn)題之volatile關(guān)鍵字詳解,可見(jiàn)性指一個(gè)線程對(duì)共享變量值的修改,能夠及時(shí)地被其他線程看到,而 volatile 關(guān)鍵字就保證內(nèi)存的可見(jiàn)性,需要的朋友可以參考下
    2023-08-08
  • MybatisPlus常用依賴、配置、插件方式

    MybatisPlus常用依賴、配置、插件方式

    這篇文章主要介紹了MybatisPlus常用依賴、配置、插件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 使用JSONObject生成和解析json的方法

    使用JSONObject生成和解析json的方法

    下面小編就為大家?guī)?lái)一篇使用JSONObject生成和解析json的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • java冒泡排序和選擇排序示例

    java冒泡排序和選擇排序示例

    這篇文章主要介紹了java冒泡排序和選擇排序示例,需要的朋友可以參考下
    2014-05-05

最新評(píng)論