ConcurrentHashMap的相关介绍和使用

概述

ConcurrentHashMap是Java中提供的一个关于线程安全的哈希表实现,他是java.util.concurrent包的一部分,允许多个读操作并发进行,提高了并发环境下的性能。ConcurrentHashMap实现了ConcurrentMap接口,故而他也有ConcurrentMap中的所有原子操作,例如putIfAbsentremovereplace

ConcurrentMap定义了一些重要的线程安全的原子操作,而ConcurrentHashMap提供了这些操作的具体实现。因此,ConcurrentHashMap继承了ConcurrentMap的所有特性,并且在此基础上进行了优化和扩展,以支持更高效的并发操作。

在这里插入图片描述

在这里插入图片描述

底层实现

在Java8之前,ConcurrentHashMap使用分段技术,将数据分成一段一段,没一段都由自己的锁,当一个线程访问一个特定的段时候,只会锁定这个段,而不会影响其他段,这样就允许多个线程并发地访问不同的段。

在Java8的时候,ConcurrentHashMap的实现被重写了,不在使用分段锁,使用了一种基于节点的锁定策略,通过使用CAS(compare and Swap) 操作和synchronized关键字来减少锁的争用。在Java 8中,ConcurrentHashMap的数据结构是一个数组 + 链表 + 红黑树的复合结构,当链表长度超过一定的阈值时候,链表会转换为红黑树,从而提高搜索效率。

优缺点

优点

  • 线程安全: 提供了线程安全的Map实现,适用于多线程环境。
  • 高并发性能:相比于Hashtable和Collections.synchronizedMap,ConcurrentHashMap提供了更好的并发性能。
  • 拓展性: 通过分离锁的机制,允许更多的并发更新操作。
  • 原子操作:支持多种原子操作,简化了并发编程。

缺点

  • 内存占用: 为了实现线程安全,可能会比非线程安全的Map实现使用更多的内存。
  • 复杂性:内部实现比较复杂,理解和使用不当会导致性能问题。

案例:

模拟实现一个简单的线程安全的缓存系统

import java.util.concurrent.ConcurrentHashMap;

public class SimpleCache<K, V> {
    private final ConcurrentHashMap<K, V> cacheMap = new ConcurrentHashMap<>();

    public V get(K key) {
        return cacheMap.get(key);
    }

    public void put(K key, V value) {
        cacheMap.put(key, value);
    }

    public void remove(K key) {
        cacheMap.remove(key);
    }

    // 其他可能的缓存操作...
}

public class CacheDemo {
    public static void main(String[] args) {
        SimpleCache<String, String> cache = new SimpleCache<>();

        // 添加缓存项
        cache.put("key1", "value1");

        // 从缓存中读取项
        String value = cache.get("key1");
        System.out.println("Cached value for key1: " + value);

        // 删除缓存项
        cache.remove("key1");
    }
}

在案例中,我们创建了一个名为SimpleCache的类,它使用ConcurrentHashMap来存储缓存项。这个简单的缓存系统是线程安全的,可以在多线程环境中使用,而不需要担心数据的一致性问题。

用来解决什么问题

ConcurrentHashMap通常用于解决需要高并发读写操作的场景,例如缓存系统、会话存储、共享资源的访问控制等。

示例代码:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class SimpleConcurrentCache<K, V> {
    private final ConcurrentHashMap<K, V> cacheMap = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<K, ReentrantLock> lockMap = new ConcurrentHashMap<>();

    public V get(K key) {
        return cacheMap.get(key);
    }

    public void put(K key, V value) {
        cacheMap.put(key, value);
    }

    public void remove(K key) {
        cacheMap.remove(key);
    }

    // 获取资源的访问锁
    public ReentrantLock getLock(K key) {
        // 使用 putIfAbsent 保证只有一个锁实例被创建
        lockMap.putIfAbsent(key, new ReentrantLock());
        return lockMap.get(key);
    }

    // 用于会话存储的方法
    public void storeSession(K sessionId, V sessionData) {
        put(sessionId, sessionData);
    }

    public V retrieveSession(K sessionId) {
        return get(sessionId);
    }

    public void removeSession(K sessionId) {
        remove(sessionId);
    }

    // 用于共享资源访问控制的方法
    public void accessResource(K resourceId, Runnable accessLogic) {
        ReentrantLock lock = getLock(resourceId);
        lock.lock();
        try {
            // 执行访问资源的逻辑
            accessLogic.run();
        } finally {
            lock.unlock();
        }
    }
}
public class CacheDemo {
    public static void main(String[] args) {
        SimpleConcurrentCache<String, String> cache = new SimpleConcurrentCache<>();

        // 存储会话数据
        cache.storeSession("user1_session", "User 1 Session Data");

        // 访问会话数据
        String sessionData = cache.retrieveSession("user1_session");
        System.out.println("Retrieved session data: " + sessionData);

        // 访问共享资源
        cache.accessResource("shared_resource", () -> {
            // 这里是访问共享资源的逻辑
            System.out.println("Accessing shared resource");
        });

        // 移除会话数据
        cache.removeSession("user1_session");
    }
}

SimpleConcurrentCache类使用ConcurrentHashMap来存储缓存数据和锁对象。我们为每个资源创建了一个ReentrantLock,以便在访问共享资源时提供同步控制。这样,我们可以确保在访问共享资源时,每次只有一个线程可以执行访问逻辑。

storeSessionretrieveSessionremoveSession方法提供了会话存储的基本操作。accessResource方法允许线程安全地访问共享资源,它首先获取资源对应的锁,然后执行访问逻辑,并在最后释放锁。

相关推荐

  1. HashTableConcurrentHashMap区别

    2024-03-19 14:48:03       19 阅读
  2. 【xilinx】使用vivado编译中methodology相关介绍

    2024-03-19 14:48:03       12 阅读
  3. npm介绍使用

    2024-03-19 14:48:03       21 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-19 14:48:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-19 14:48:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-19 14:48:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-19 14:48:03       20 阅读

热门阅读

  1. 设计模式的六大基本原则

    2024-03-19 14:48:03       17 阅读
  2. 使用 C 或 C++ 扩展 Python

    2024-03-19 14:48:03       21 阅读
  3. 判断两个IP是否在同一网段(SHELL实现)

    2024-03-19 14:48:03       22 阅读
  4. 人工智能迷惑行为大赏

    2024-03-19 14:48:03       20 阅读
  5. 嵌入式开发常用工具汇总

    2024-03-19 14:48:03       22 阅读
  6. 蓝桥杯C++大学B组一个月冲刺记录2024/3/18

    2024-03-19 14:48:03       20 阅读
  7. IPC之管道

    2024-03-19 14:48:03       19 阅读
  8. 鸿蒙ArkTS语言快速入门-TS(五)

    2024-03-19 14:48:03       23 阅读
  9. 责任链模式

    2024-03-19 14:48:03       15 阅读