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

ConcurrentHashMap原理及使用詳解

 更新時間:2023年06月08日 10:21:56   作者:蜀山劍客李沐白  
ConcurrentHashMap是Java中的一種線程安全的哈希表實現(xiàn),它提供了與Hashtable和HashMap類似的API,是一個高效且可靠的多線程環(huán)境下的哈希表實現(xiàn),非常適合在并發(fā)場景中使用,本文就簡單介紹一下ConcurrentHashMap原理及使用,需要的朋友可以參考下

ConcurrentHashMap是Java中的一種線程安全的哈希表實現(xiàn),它提供了與Hashtable和HashMap類似的API,但通過使用分段鎖技術(Segment),使得多個線程可以同時讀取和寫入不同的數(shù)據(jù)塊,從而提高了并發(fā)性能。同時,ConcurrentHashMap也支持弱一致性,即在某些情況下,讀取操作可能會返回稍早的值,但這對于很多應用場景來說是可以接受的。該類還提供了一些有用的方法,如putIfAbsent()、replace()、compute()等,方便開發(fā)者進行基于哈希表的數(shù)據(jù)處理。總之,ConcurrentHashMap是一個高效且可靠的多線程環(huán)境下的哈希表實現(xiàn),非常適合在并發(fā)場景中使用。

一、ConcurrentHashMap 的數(shù)據(jù)結構

ConcurrentHashMap 是 Java 中的一種線程安全的哈希表實現(xiàn),其數(shù)據(jù)結構是由多個 Node 節(jié)點組成的數(shù)組和鏈表或紅黑樹。

在 ConcurrentHashMap 中,Node 節(jié)點是一個鍵值對,其中鍵為 K 類型,值為 V 類型。每個節(jié)點包含了一個哈希值、一個鍵和一個值,以及指向下一個節(jié)點的引用。具體而言,ConcurrentHashMap 的內部數(shù)據(jù)結構如下:

ConcurrentHashMap 中的每個 Segment 是一個獨立的哈希表,而每個 Segment 又由多個 Bucket 組成,每個 Bucket 再維護一個鏈表或紅黑樹(紅黑樹出現(xiàn)的條件是 Bucket 中的元素數(shù)量大于等于 8)。

ConcurrentHashMap 的 put 操作可以分成兩個步驟,首先根據(jù) Key 的哈希值找到對應的 Segment 和 Bucket,然后在 Bucket 中插入新的 Node 節(jié)點。具體來說,它的處理流程如下:

  • 對 Key 進行哈希操作,得到其哈希值。
  • 根據(jù)哈希值和 Segment 數(shù)組的長度,計算出 Key 應該被放在哪個 Segment 中。
  • 在 Segment 中獲取 Key 應該放在哪個 Bucket 中。
  • 如果該 Bucket 是空的,則直接在它的頭部插入新的 Node 節(jié)點;否則,將新的 Node 節(jié)點插入到鏈表的尾部或紅黑樹上,并根據(jù)情況進行擴容或紅黑樹轉換為鏈表。
  • 如果插入新的節(jié)點后 Bucket 中的元素數(shù)量超過了一個閾值,則需要進行擴容操作。
  • 如果插入新的節(jié)點后 Bucket 中的元素數(shù)量大于等于 8 個并且 Bucket 不是紅黑樹,則需要將鏈表轉換為紅黑樹。
  • 如果舊的紅黑樹中的節(jié)點數(shù)量少于 6 個,則需要將紅黑樹轉換為鏈表。

ConcurrentHashMap 的 get 操作也很簡單,直接根據(jù) Key 的哈希值找到對應的 Segment 和 Bucket,然后在 Bucket 中查找對應的 Node 節(jié)點即可。

二、ConcurrentHashMap 的分段鎖機制

ConcurrentHashMap 將整個哈希表分為多個 Segment,每個 Segment 又是一個獨立的哈希表,可以單獨進行加鎖和擴容操作。在操作數(shù)據(jù)時,只需要獲取對應 Segment 的鎖,不需要鎖住整個哈希表,這樣可以避免多個線程之間的等待和競爭,同時提高吞吐量和并發(fā)性能。

簡單實現(xiàn)示例:

class ConcurrentHashMap<K, V> {
    final Segment[] segments;
    class Segment extends ReentrantLock implements Serializable{
        // 每個 Segment 自己獨立的哈希表
        private final Map<K,V> map = new HashMap<>();
        // Segment 內部加鎖機制,確保線程安全
        public synchronized V put(K key, V value) {
            return map.put(key, value);
        }
    }
    // 獲取 key 所屬的 Segment 的索引
    private int getSegmentIndex(K key) {
        int hash = hash(key.hashCode()); // 對 hashcode() 進行哈希
        int segmentMask = segments.length - 1; // mask 值
        return hash & segmentMask; // 按位與,定位具體的 Segment
    }
    public V put(K key, V value) {
        Segment s = segments[getSegmentIndex(key)];
        s.lock(); // 獲取 s 對應的 Segment 的鎖
        try {
            return s.put(key, value); // 在 s 上進行 put 操作
        } finally {
            s.unlock(); // 釋放 s 對應的 Segment 的鎖
        }
    }
}

在實際的 ConcurrentHashMap 中,每個 Segment 會使用一個獨立的哈希表來維護其內部的數(shù)據(jù),同時也具備自己的鎖機制,從而實現(xiàn)對其內部狀態(tài)的并發(fā)安全訪問。這樣,不同線程訪問不同的 Segment 時可以通過分段鎖機制來實現(xiàn)并發(fā)訪問,從而提高了 ConcurrentHashMap 的并發(fā)性能和吞吐量。

三、ConcurrentHashMap 的實現(xiàn)過程

在 JDK 1.8 以前,ConcurrentHashMap 的實現(xiàn)采用了與 Hashtable 類似的分段鎖機制,每個 Segment 都對應一個 ReentrantLock 鎖,用于并發(fā)訪問。

而在 JDK 1.8 中,ConcurrentHashMap 引入了 CAS(Compare and Swap)技術,用于實現(xiàn)一個更加高效的并發(fā)控制機制。CAS 是一種無鎖機制,可以避免線程爭搶鎖的情況。

我們以 put 操作為例,來看一下 ConcurrentHashMap 的實現(xiàn)過程:

  • 首先計算 key 的哈希值;
  • 根據(jù)哈希值找到對應的 Segment;
  • 獲取 Segment 對應的鎖;
  • 如果還沒有元素,就直接插入到 Segment 中;
  • 如果已經(jīng)存在元素,就循環(huán)比較 key 是否相等;
  • 如果 key 已經(jīng)存在,就根據(jù)要求更新 value;
  • 如果 key 不存在,就插入新的元素(鏈表或者紅黑樹)。

上述操作中,步驟 2 到 3 相當于加了一個悲觀鎖,在整個哈希表上加鎖,如果只有一個 Segment,效果與 Hashtable 類似;如果存在多個 Segment,效果就相當于使用了分段鎖機制,提高了并發(fā)訪問性能。

四、使用場景案例

1. 高并發(fā)的計數(shù)器

ConcurrentHashMap 可以用來實現(xiàn)高并發(fā)的計數(shù)器,例如記錄網(wǎng)站訪問量、接口調用次數(shù)等。具體地,我們可以使用 ConcurrentHashMap 的 compute 方法來實現(xiàn)計數(shù)操作,如下所示:

import java.util.concurrent.ConcurrentHashMap;
public class Counter {
    private final ConcurrentHashMap<String, Integer> map;
    public Counter() {
        this.map = new ConcurrentHashMap<>();
    }
    public void increase(String key) {
        map.compute(key, (k, v) -> (v == null) ? 1 : v + 1);
    }
    public int get(String key) {
        return map.getOrDefault(key, 0);
    }
}

在上述代碼中,我們創(chuàng)建了一個 Counter 類,使用 ConcurrentHashMap 存儲計數(shù)器數(shù)據(jù)。具體地,我們使用 compute 方法實現(xiàn)對計數(shù)器的增加操作,如果 key 不存在則新建一個值為 1 的計數(shù)器;否則將其遞增 1。通過 get 方法可以獲取指定 key 對應的計數(shù)器值。

2. 線程池任務管理

ConcurrentHashMap 還可以用來實現(xiàn)線程池任務的管理,例如記錄每個任務的執(zhí)行狀態(tài)、結果等信息。具體地,我們可以將一個 ConcurrentHashMap 實例作為任務管理器,在任務執(zhí)行前將任務信息添加到該管理器中,然后再在任務完成后更新對應的信息,如下所示:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TaskManager {
    private final ConcurrentHashMap<String, TaskInfo> tasks;
    public TaskManager() {
        this.tasks = new ConcurrentHashMap<>();
    }
    public void addTask(String taskId, Runnable task) {
        // 添加任務信息
        tasks.put(taskId, new TaskInfo());
        // 提交任務到線程池
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.submit(() -> {
            try {
                // 執(zhí)行任務
                task.run();
                // 更新任務狀態(tài)和結果
                TaskInfo info = tasks.get(taskId);
                info.setStatus(TaskStatus.COMPLETED);
                info.setResult("Task completed successfully!");
            } catch (Exception ex) {
                // 更新任務狀態(tài)和結果
                TaskInfo info = tasks.get(taskId);
                info.setStatus(TaskStatus.FAILED);
                info.setResult(ex.getMessage());
            }
        });
        // 關閉線程池
        executor.shutdown();
    }
    public TaskInfo getTaskInfo(String taskId) {
        return tasks.getOrDefault(taskId, new TaskInfo());
    }
}
enum TaskStatus {
    NEW,
    RUNNING,
    COMPLETED,
    FAILED;
}
class TaskInfo {
    private TaskStatus status;
    private String result;
    public TaskInfo() {
        this.status = TaskStatus.NEW;
        this.result = "";
    }
    public TaskStatus getStatus() {
        return status;
    }
    public void setStatus(TaskStatus status) {
        this.status = status;
    }
    public String getResult() {
        return result;
    }
    public void setResult(String result) {
        this.result = result;
    }
}

在上述代碼中,我們創(chuàng)建了一個 TaskManager 類,使用 ConcurrentHashMap 存儲任務信息。具體地,我們定義了一個 TaskInfo 類來表示任務信息,其中包括任務狀態(tài)和結果兩個屬性。在添加任務時,我們新建一個 TaskInfo 實例并添加到 ConcurrentHashMap 中,然后在異步執(zhí)行任務的線程中更新其狀態(tài)和結果;同時我們使用 ExecutorService 來管理并發(fā)執(zhí)行的任務。通過 getTaskInfo 方法可以獲取指定 taskId 對應的任務信息。

3. 緩存管理器

ConcurrentHashMap 還可以用來實現(xiàn)緩存管理器,例如存儲經(jīng)常使用的業(yè)務數(shù)據(jù)、系統(tǒng)配置等信息,從而避免頻繁的數(shù)據(jù)庫查詢或網(wǎng)絡請求。具體地,我們可以使用 ConcurrentHashMap 存儲緩存數(shù)據(jù),并設定緩存過期時間,如下所示:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class CacheManager<K, V> {
    private final Map<K, CacheEntry<V>> cache;
    public CacheManager() {
        this.cache = new ConcurrentHashMap<>();
    }
    public void put(K key, V value, long ttl) {
        // 添加緩存項,同時記錄當前時間戳和緩存生存時間
        CacheEntry<V> entry = new CacheEntry<>(value, System.currentTimeMillis(), ttl);
        cache.put(key, entry);
    }
    public V get(K key) {
        // 獲取緩存項和其緩存生存時間
        CacheEntry<V> entry = cache.get(key);
        // 檢查緩存項是否過期,如果過期則刪除緩存項并返回 null
        if (entry != null && !entry.isExpired()) {
            return entry.getValue();
        } else {
            cache.remove(key);
            return null;
        }
    }
    static class CacheEntry<V> {
        private final V value;
        private final long timestamp;
        private final long ttl;
        public CacheEntry(V value, long timestamp, long ttl) {
            this.value = value;
            this.timestamp = timestamp;
            this.ttl = ttl;
        }
        public V getValue() {
            return value;
        }
        public boolean isExpired() {
            return System.currentTimeMillis() - timestamp > ttl;
        }
    }
}

在上述代碼中,我們創(chuàng)建了一個 CacheManager 類,使用 ConcurrentHashMap 存儲緩存數(shù)據(jù)。具體地,我們定義了一個 CacheEntry 類來表示緩存項,其中包括值、時間戳和緩存生存時間三個屬性。在添加緩存項時,我們新建一個 CacheEntry 實例并添加到 ConcurrentHashMap 中,然后在獲取緩存項時檢查其是否過期;如果未過期則返回其值,否則刪除緩存項并返回 null。

以上就是ConcurrentHashMap 原理及使用詳解的詳細內容,更多關于ConcurrentHashMap 原理及用法的資料請關注腳本之家其它相關文章!

相關文章

  • 淺談spring注解之@profile

    淺談spring注解之@profile

    這篇文章主要介紹了淺談spring注解之@profile,@profile通過配置來改變參數(shù),這里整理的詳細的用法,有興趣的可以了解一下
    2017-10-10
  • Java線程池的分析和使用詳解

    Java線程池的分析和使用詳解

    本篇文章主要介紹了Java線程池的分析和使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-11-11
  • springBoot項目中的static和templates文件夾的使用

    springBoot項目中的static和templates文件夾的使用

    本文主要介紹了springBoot項目中的static和templates文件夾的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-07-07
  • Java二維數(shù)組與動態(tài)數(shù)組ArrayList類詳解

    Java二維數(shù)組與動態(tài)數(shù)組ArrayList類詳解

    這篇文章主要給大家介紹了關于Java二維數(shù)組與動態(tài)數(shù)組ArrayList類的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Java多線程導致CPU占用100%解決及線程池正確關閉方式

    Java多線程導致CPU占用100%解決及線程池正確關閉方式

    1000萬表數(shù)據(jù)導入內存數(shù)據(jù)庫,按分頁大小10000查詢,多線程,15條線程跑,最后發(fā)現(xiàn)CPU占用100%卡死,那么如何解決,本文就來介紹一下,感興趣的朋友可以了解一下
    2021-05-05
  • Spring的@PropertySource注解源碼解析

    Spring的@PropertySource注解源碼解析

    這篇文章主要介紹了Spring的@PropertySource注解源碼解析,就以源碼時序圖的方式,直觀的感受下@PropertySource注解在Spring源碼層面的執(zhí)行流程,需要的朋友可以參考下
    2023-11-11
  • IDEA2022.2的簡介、下載與安裝、配置教程

    IDEA2022.2的簡介、下載與安裝、配置教程

    IDEA是JetBrains公司推出一個集成開發(fā)工具,是Java開發(fā)工具中的翹楚,基于這個開發(fā)工具可以快速開發(fā)我們的Java相關項目,本文重點給大家介紹IDEA2022.2的簡介、下載與安裝、初步配置,感興趣的朋友一起看看吧
    2022-11-11
  • spring+springmvc+mybatis+maven入門實戰(zhàn)(超詳細教程)

    spring+springmvc+mybatis+maven入門實戰(zhàn)(超詳細教程)

    這篇文章主要介紹了spring+springmvc+mybatis+maven入門實戰(zhàn)(超詳細教程),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • 一文讓你了解透徹Java中的IO模型

    一文讓你了解透徹Java中的IO模型

    本文只是說明了IO模型,讓你了解IO模型是什么,怎么區(qū)分IO模型,以及分析了Java中的三種IO模型,本文是純理論知識,看完之后會讓你對IO有更加深刻的理解,感興趣的同學可以參考一下
    2023-05-05
  • SpringBoot?docker項目部署實戰(zhàn)

    SpringBoot?docker項目部署實戰(zhàn)

    本文主要介紹了SpringBoot?docker項目部署實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-08-08

最新評論

石棉县| 宁南县| 南江县| 姜堰市| 开鲁县| 衡山县| 揭西县| 全椒县| 平武县| 左云县| 临汾市| 广安市| 区。| 定兴县| 东平县| 庄河市| 花莲市| 岱山县| 呈贡县| 濮阳市| 荣成市| 肃宁县| 从江县| 大足县| 绍兴县| 越西县| 红河县| 盐池县| 汽车| 灵璧县| 潍坊市| 五峰| 麟游县| 山丹县| 开鲁县| 台南县| 永春县| 嘉义县| 沐川县| 兰坪| 武冈市|