第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Java并發(fā)工具 Java并發(fā)工具 寫時復(fù)制的CopyOnWriteArrayList

寫時復(fù)制的 CopyOnWriteArrayList

1. 前言

本節(jié)帶領(lǐng)大家認(rèn)識第二個常用的 Java 并發(fā)容器類之 CopyOnWriteArrayList。

本節(jié)先介紹 CopyOnWriteArrayList 工具類表達(dá)的概念和最基本用法,接著通過一個生活中的例子為大家解釋 CopyOnWriteArrayList 工具類的使用場合,然后通過簡單的編碼實現(xiàn)此場景。

下面我們正式開始介紹吧。

2. 概念解釋

什么是 CopyOnWrite ? 顧名思義,就是 “寫數(shù)據(jù)的時候先拷貝一份副本,在副本上寫數(shù)據(jù)”。為什么需要在寫的時候以這種方式執(zhí)行呢?當(dāng)然是為了提高效率。

當(dāng)多個線程同時操作一個 ArrayList 對象時,為了線程安全需要對操作增加線程安全相關(guān)的鎖控制。采用 CopyOnWrite 方式,可以做到讀操作不用加鎖,而只對寫操作加鎖,且可以很方便地反饋寫后的結(jié)果給到讀操作。CopyOnWriteArrayList 就是采用這種優(yōu)化思想,對 ArrayList 做的線程安全特性增強(qiáng)。我們通過一張圖了解其基本原理。
圖片描述
概念已經(jīng)了解了,CopyOnWriteArrayList 工具類最基本的用法是怎樣的呢?看下面。

3. 基本用法

此工具類和 ArrayList 在使用方式方面很類似。

// 創(chuàng)建一個 CopyOnWriteArrayList 對象
CopyOnWriteArrayList phaser = new CopyOnWriteArrayList();
// 新增
copyOnWriteArrayList.add(1);
// 設(shè)置(指定下標(biāo))
copyOnWriteArrayList.set(0, 2);
// 獲?。ú樵儯?/span>
copyOnWriteArrayList.get(0);
// 刪除
copyOnWriteArrayList.remove(0);
// 清空
copyOnWriteArrayList.clear();
// 是否為空
copyOnWriteArrayList.isEmpty();
// 是否包含
copyOnWriteArrayList.contains(1);
// 獲取元素個數(shù)
copyOnWriteArrayList.size();

是不是很簡單,那 CopyOnWriteArrayList 應(yīng)用在哪些場合比較合適呢?下面我們給出最常用的場景說明。

4. 常用場景

CopyOnWriteArrayList 并發(fā)容器用于讀多寫少的并發(fā)場景。因為采用了寫時復(fù)制的實現(xiàn)原理,當(dāng)存在大量寫的時候,內(nèi)存中會頻繁復(fù)制原有數(shù)據(jù)的副本,如果原有數(shù)據(jù)集很大,則很容易造成內(nèi)存飆升甚至內(nèi)存異常。在日常研發(fā)中,可用于靜態(tài)數(shù)據(jù)字典的緩存場合,如黑白名單過濾判定。

注意,CopyOnWriteArrayList 不能保證寫入的數(shù)據(jù)實時讀取到,只保證數(shù)據(jù)的最終一致。是因為寫入時需要復(fù)制一份原有內(nèi)容,以及寫入后的新老內(nèi)容互換都需要一定時間。

我們舉一個 IP 黑名單判定的例子:當(dāng)應(yīng)用接入外部請求后,為了防范風(fēng)險,一般會對請求做一些特征判定,如對請求 IP 是否合法的判定就是一種。IP 黑名單偶爾會被系統(tǒng)運維人員做更新。我們使用 CopyOnWriteArrayList 工具類實現(xiàn)此場景,請看下面代碼。

5. 場景案例

import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListTest {

    // 創(chuàng)建一個 CountDownLatch 對象,代表黑名單列表
    private static CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
    // 模擬初始化的黑名單數(shù)據(jù)
    static {
        copyOnWriteArrayList.add("ipAddr0");
        copyOnWriteArrayList.add("ipAddr1");
        copyOnWriteArrayList.add("ipAddr2");
    }

    // 主線程
    public static void main(String[] args) throws InterruptedException {
        Runnable task = new Runnable() {
            public void run() {
                // 模擬接入用時
                try {
                    Thread.sleep(new Random().nextInt(5000));
                } catch (Exception e) {}

                String currentIP = "ipAddr" + new Random().nextInt(5);
                if (copyOnWriteArrayList.contains(currentIP)) {
                    System.out.println(Thread.currentThread().getName() + " IP " + currentIP + "命中黑名單,拒絕接入處理");
                    return;
                }
                System.out.println(Thread.currentThread().getName() + " IP " + currentIP + "接入處理...");
            }
        };
        new Thread(task, "請求1").start();
        new Thread(task, "請求2").start();
        new Thread(task, "請求3").start();

        Runnable updateTask = new Runnable() {
            public void run() {
                // 模擬用時
                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (Exception e) {}

                String newBlackIP = "ipAddr3";
                copyOnWriteArrayList.add(newBlackIP);
                System.out.println(Thread.currentThread().getName() + " 添加了新的非法IP " + newBlackIP);
            }
        };
        new Thread(updateTask, "IP黑名單更新").start();

        Thread.sleep(1000000);
    }
}

運行上面代碼,我們觀察一下運行結(jié)果。

請求2 IP ipAddr1命中黑名單,拒絕接入處理
IP黑名單更新 添加了新的非法IP ipAddr3
請求3 IP ipAddr3命中黑名單,拒絕接入處理
請求1 IP ipAddr4接入處理...

觀察結(jié)果,和我們的預(yù)期一致。

6. 小結(jié)

本節(jié)通過一個簡單的例子,介紹了 CopyOnWriteArrayList 的使用場景和基本用法。希望大家在學(xué)習(xí)過程中,多思考勤練習(xí),早日掌握之。