最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的CopyOnWriteArrayList原理詳解

 更新時(shí)間:2023年12月27日 10:58:10   作者:笑我歸無處  
這篇文章主要介紹了Java中的CopyOnWriteArrayList原理詳解,如源碼所示,CopyOnWriteArrayList和ArrayList一樣,都在內(nèi)部維護(hù)了一個(gè)數(shù)組,操作CopyOnWriteArrayList其實(shí)就是在操作內(nèi)部的數(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一樣,都在內(nèi)部維護(hù)了一個(gè)數(shù)組。操作CopyOnWriteArrayList其實(shí)就是在操作內(nèi)部的數(shù)組。

但關(guān)鍵是和ArrayList的不同之處

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

private transient volatile Object[] array;

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

2) 加鎖

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

final transient ReentrantLock lock = new ReentrantLock();

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

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操作沒有加鎖,直接返回?cái)?shù)組中的對(duì)象。

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ù)組內(nèi)容沒變)
  • 釋放鎖

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ù)組
  • 復(fù)制一個(gè)源數(shù)組長(zhǎng)度+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ù)組末尾
  • 是末尾的話,復(fù)制一個(gè)數(shù)組長(zhǎng)度減一的數(shù)組,然后更新源數(shù)組
  • 不是末尾的話,做成一個(gè)不包含需要?jiǎng)h除的元素的新數(shù)組,然后更新源數(shù)組
  • 釋放鎖

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

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

讀操作為什么不加鎖

當(dāng)然是為了提高讀操作的效率啦

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

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

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

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

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

CopyOnWriteArrayList的優(yōu)缺點(diǎn)

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

缺點(diǎn): 因?yàn)槊看螌懖僮鞫夹枰獜?fù)制一份新數(shù)組,所以寫操作性能低下,尤其是數(shù)組長(zhǎng)度很長(zhǎng)時(shí),不建議使用CopyOnWriteArrayList。

CopyOnWriteArrayList的應(yīng)用場(chǎng)景

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

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

相關(guān)文章

  • SpringBoot整合Elasticsearch7.2.0的實(shí)現(xiàn)方法

    SpringBoot整合Elasticsearch7.2.0的實(shí)現(xiàn)方法

    這篇文章主要介紹了SpringBoot整合Elasticsearch7.2.0的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • SpringBoot自定義RestTemplate的攔截器鏈的實(shí)戰(zhàn)指南

    SpringBoot自定義RestTemplate的攔截器鏈的實(shí)戰(zhàn)指南

    在項(xiàng)目開發(fā)中,RestTemplate作為Spring提供的HTTP客戶端工具,經(jīng)常用于訪問內(nèi)部或三方服務(wù),但在實(shí)際項(xiàng)目中,我們往往需要對(duì)請(qǐng)求進(jìn)行統(tǒng)一處理,所以本文給大家介紹了SpringBoot自定義RestTemplate的攔截器鏈的實(shí)戰(zhàn)指南,需要的朋友可以參考下
    2025-07-07
  • Java利用Spire.Doc實(shí)現(xiàn)RTF轉(zhuǎn)換PDF的高效方案

    Java利用Spire.Doc實(shí)現(xiàn)RTF轉(zhuǎn)換PDF的高效方案

    在企業(yè)級(jí)應(yīng)用開發(fā)中,RTF格式雖因其良好的兼容性曾在文檔交換領(lǐng)域占據(jù)一席之地,但隨著移動(dòng)辦公和長(zhǎng)期歸檔需求的增加,其跨平臺(tái)顯示不一致、易被篡改的弊端日益凸顯,本文將介紹如何利用Spire.Doc for Java這一強(qiáng)大的類庫(kù)實(shí)現(xiàn)將RTF轉(zhuǎn)換為PDF,需要的朋友可以參考下
    2026-03-03
  • Java中的ReadWriteLock讀寫鎖詳解

    Java中的ReadWriteLock讀寫鎖詳解

    這篇文章主要介紹了Java中的ReadWriteLock讀寫鎖詳解,ReadWriteLock也是一個(gè)接口,提供了readLock和writeLock兩種鎖的操作機(jī)制,一個(gè)資源可以被多個(gè)線程同時(shí)讀,或者被一個(gè)線程寫,但是不能同時(shí)存在讀和寫線程,需要的朋友可以參考下
    2023-12-12
  • springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)圖文教程

    springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)圖文教程

    這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目(jar包)指定配置文件啟動(dòng)的相關(guān)資料,在多環(huán)境部署過程中、及線上運(yùn)維中可能會(huì)遇到臨時(shí)指定配置文件的情況,需要的朋友可以參考下
    2023-07-07
  • Spring Boot日志收集及鏈路追蹤實(shí)現(xiàn)示例

    Spring Boot日志收集及鏈路追蹤實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了Spring Boot日志收集及鏈路追蹤實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • SpringCloud Config使用配置方法

    SpringCloud Config使用配置方法

    這篇文章給大家介紹SpringCloud Config使用及構(gòu)建配置中心的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-07-07
  • 使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn)

    使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn)

    這篇文章主要介紹了使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 詳解SpringBoot簡(jiǎn)化配置分析總結(jié)

    詳解SpringBoot簡(jiǎn)化配置分析總結(jié)

    這篇文章主要介紹了詳解SpringBoot簡(jiǎn)化配置分析總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • spring啟動(dòng)后保證創(chuàng)建的對(duì)象不被垃圾回收器回收

    spring啟動(dòng)后保證創(chuàng)建的對(duì)象不被垃圾回收器回收

    最近看到一個(gè)問題是,spring在啟動(dòng)后如何保證創(chuàng)建的對(duì)象不被垃圾回收器回收?。所以本文結(jié)合jvm的垃圾回收機(jī)制和spring中的源代碼做出自己的一點(diǎn)猜測(cè)。有需要的朋友們可以參考借鑒。
    2016-09-09

最新評(píng)論

鹰潭市| 元谋县| 兴安盟| 屏山县| 静安区| 若羌县| 太原市| 棋牌| 剑河县| 丰台区| 桐城市| 浙江省| 临沧市| 民丰县| 项城市| 盐城市| 保靖县| 衡阳市| 龙门县| 榆中县| 龙州县| 汝阳县| 黄石市| 惠东县| 宝山区| 昌黎县| 成安县| 西平县| 专栏| 碌曲县| 黄浦区| 凌海市| 酉阳| 左贡县| 临武县| 丰城市| 合阳县| 清水县| 宝鸡市| 南城县| 莒南县|