亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用CopyOnWriteArrayList

發布時間:2021-10-21 09:48:37 來源:億速云 閱讀:277 作者:iii 欄目:編程語言

本篇內容主要講解“怎么使用CopyOnWriteArrayList”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用CopyOnWriteArrayList”吧!

一、Vector集合源碼簡析

由于本文的重點不是Vector集合,因此只是簡單的分析一下Vector的初始化方法和添加元素的方法。

Vector的底層實現和ArrayList一樣,都是由數組實現的。

Vector的主要變量如下:

/**
 * 存放元素的數組
 */
protected Object[] elementData;
/**
 * 元素個數
 */
protected int elementCount;
/**
 * 擴容自增容量大小
 */
protected int capacityIncrement;
1.1 Vector初始化

Vector的初始化提供了三個方法,除了可以指定初始容量的大小,還可以指定擴容容量的大小。構造器分別如下:

無參構造器

public Vector() {
    this(10);
}

指定初始化容量的構造器

public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}

指定初始化容量和擴容容量大小的構造器

public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

從上面的構造器中可以看出,如果調用無參構造器,則會創建一個初始化容量為10,擴容容量為0Vector集合。

1.2 如何擴容

Vector的擴容機制和ArrayList的很像,如果不清楚ArrayList的擴容機制,可以看看這篇文章。這里我們直接看Vector的擴容方法grow

private void grow(int minCapacity) {
    // overflow-conscious code
    // 初始化數組的長度,默認為10
    int oldCapacity = elementData.length;
    // 是否指定擴容容量,不指定擴容為原來的2倍
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

通過上面的方法,我們可以看出,如果指定了擴容容量的大小則擴容的新數組大小為原來的數組加上擴容容量的大小,如果不指定擴容容量的大小則擴容的新數組大小為原來數組大小的2倍。這樣擴容為原來的2倍是很消耗空間的,這也是Vector被棄用的原因之一。

除此之外,看過源碼的同學可能發現了,Vector集合的所有操作元素的方法都加了synchronized關鍵字,這就導致了操作Vector的效率會非常低,在開發中,往往讀操作的使用頻率會遠高于其他操作,而CopyOnWriteArrayList 就是這樣一種讀操作效率遠高于寫操作效率的List,一起來看看。

二、CopyOnWriteArrayList源碼簡析

CopyOnWriteArrayList 類圖:

怎么使用CopyOnWriteArrayList

2.1 CopyOnWrite思想

CopyOnWrite簡稱COW,根據名字來看就是寫入時復制。意思就是大家共同去訪問一個資源,如果有人想要去修改這個資源的時候,就需要復制一個副本,去修改這個副本,而對于其他人來說訪問得資源還是原來的,不會發生變化。

2.2 初始化CopyOnWriteArrayList

CopyOnWriteArrayList 底層是也是有數組實現的。 本文我們只解讀添加元素和讀取元素的區別,刪除修改元素原理和添加元素差不多,操作時都需要進行加鎖,而讀操作不會加鎖。

CopyOnWriteArrayList 主要有以下兩個變量:

// 獨占鎖
final transient ReentrantLock lock = new ReentrantLock();

// 存放元素的數組
private transient volatile Object[] array;

我們仔細來分析一下上面兩個屬性,這兩個思想是 CopyOnWriteArrayList 的核心 。

  • lock:ReentrantLock,獨占鎖,多線程運行的情況下,只有一個線程會獲得這個鎖,只有釋放鎖后其他線程才能獲得。

  • array:存放數據的數組,關鍵是被volatile修飾了,被volatile修飾,就保證了可見性,也就是一個線程修改后,其他線程立即可見。

最常用的初始化方式如下:

/**
  * Creates an empty list.
  */
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}

/**
  * Sets the array.
  */
final void setArray(Object[] a) {
    array = a;
}

初始化只是創建了一個空的數組,并將array指向它。

2.3 添加元素
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // 獲取原來的數組
        Object[] elements = getArray();
        // 原來數組的長度
        int len = elements.length;
        // 創建一個長度+1的新數組,并將原來數組的元素復制給新數組
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        // 元素放在新數組末尾
        newElements[len] = e;
        // array指向新數組
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

添加數組的步驟如下:

  1. 獲得獨占鎖,將添加功能加鎖

  2. 獲取原來的數組,并得到其長度

  3. 創建一個長度為原來數組長度+1的數組,并拷貝原來的元素給新數組

  4. 追加元素到新數組末尾

  5. 指向新數組

  6. 釋放鎖

這個過程是線程安全的,COW的核心思想就是每次修改的時候拷貝一個新的資源去修改,add()方法再拷貝新資源的時候將數組容量+1,這樣雖然每次添加元素都會浪費一定的空間,但是數組的長度正好是元素的長度,也在一定程度上節省了擴容的開銷。

2.4 獲取元素
public E get(int index) {
    return get(getArray(), index);
}

final Object[] getArray() {
    return array;
}

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

讀操作是天然安全的操作,而且數組本身會進行檢查越界問題,因此獲取元素的方法很簡單,只是根據索引獲取該元素。

public int size() {
    return getArray().length;
}

由于CopyOnWriteArrayList的底層數組長度,本身就是元素大小,因此size()方法只要返回數組長度就可以了。

到此,相信大家對“怎么使用CopyOnWriteArrayList”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安龙县| 东乌珠穆沁旗| 清远市| 绵竹市| 宜宾市| 泌阳县| 陆丰市| 柳州市| 民县| 丹阳市| 临江市| 龙井市| 惠安县| 苏尼特右旗| 会理县| 蕉岭县| 克拉玛依市| 东兰县| 肇州县| 原阳县| 新泰市| 瑞丽市| 基隆市| 江都市| 广饶县| 全椒县| 东台市| 灵丘县| 时尚| 霍城县| 乃东县| 丹棱县| 宜阳县| 梨树县| 平泉县| 渭源县| 嘉祥县| 秦皇岛市| 凯里市| 万载县| 宜兰市|