ConcurrentHashMap

HashTable 与HashMap区别

1.HashTable 线程是安全的 (使用synchronized)

2.HashMap 线程是不安全 (没有使用锁)

3.HashMap 允许存放key值 null 存放在 index=0位置

4.HashTable 不允许存放key为null 

详细:

1,HashMap实现不同步,线程不安全。 HashTable线程安全 HashMap中的key-value都是存储在Entry中的。

2,继承不同。

        Hashtable 继承 Dictionary 类,而 HashMap 继承 AbstractMap

        public class Hashtable extends Dictionary implements Map

        public class HashMap extends AbstractMap implements Map

3, Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。

4, Hashtable 中, key 和 value 都不允许出现 null 值。 在 HashMap 中, null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null 。

        当get() 方法返回 null 值时,即可以表示 HashMap 中没有该键,也可以表示该键所对应的值为 null 。因此,在 HashMap 中不能由 get() 方法来判断HashMap 中是否存在某个键, 而应该用 containsKey() 方法来判断。

5,哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值

为什么不使用Hashtable?

HashTable 底层 通过 synchronized 保证线程安全性问题

保证线程安全性问题---加上锁---发生锁的竞争

HashTable 当多个线程 在访问 get或者put操作的时候会发生this锁的竞争,多个线程竞争锁 最终只会有一个线程获取到this锁,获取不到的this锁 可能会阻塞等待。最终将我们的 HashTable 中 get 或者put方法改成单线程执行 效率是非常的低。

在多线程的情况下 不推荐使用 HashTable ConcurrentHashMap

1.使用传统HashTable保证线程问题,是采用synchronized锁将整个HashTable中的数组锁住,

在多个线程中只允许一个线程访问Put或者Get,效率非常低,但是能够保证线程安全问题。

2.Jdk官方不推荐在多线程的情况下使用HashTable或者HashMap,建议使用ConcurrentHashMap分段HashMap,效率非常高。

核心思想:减少多个线程锁竞争 不会在访问同一个HashTable。

ConcurrentHashMap 1.7

就是将一个大的HashTable集合拆分成n多个小的HashTable集合 默认16个。----分段锁设计

在多线程的情况下访问到我们的ConcurrentHashMap 1.7版本做写的操作,如果多个线程写入的key 最终计算落地到不同小的HashTable集合中,就可以实现多线程同时写入key 不会发生锁的竞争。如果多个线程写入的key 最终计算落地到同一个小的HashTable集合中,就会发生锁的竞争。

ConcurrentHashMap 1.8取消了分段锁设计

ConcurrentHashMap get方法没有锁的竞争

HashTable get方法有锁的竞争

ConcurrentHashMap 1.7底层实现原理

3.ConcurrentHashMap将一个大的HashTable集合拆分成n多个不同的小的HashTable(Segment),默认的情况下是分成16个不同的Segment。每个Segment中都有自己独立的HashEntry<K,V>[] table;

手写ConcurrentHashMap1.7

public class ConcurrentHashMap<K, V> {
    private Hashtable<K, V>[] segments;

    public ConcurrentHashMap() {
        // 初始化segments 数组
        segments = new Hashtable[16];
        for (int i = 0; i < segments.length; i++) {
            segments[i] = new Hashtable<>();
        }
    }

    public void put(K k, V v) {
        // 计算key 存放具体 的Hashtable
        int segmentIndex = k.hashCode() % segments.length;
        Hashtable<K, V> hashtable = segments[segmentIndex];
        hashtable.put(k, v);
    }

    public V get(K k, V v) {
        int segmentIndex = k.hashCode() % segments.length;
        Hashtable<K, V> hashtable = segments[segmentIndex];
        return hashtable.get(k);
    }

    public static void main(String[] args) {
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("a", "a");
        hashMap.put(97, 97);
        System.out.println(hashMap.get("a"));
        System.out.println(hashMap.get(97));
    }
}

        ConcurrentHashMap 底层采用 分段锁设计 将一个大的HashTable线程安全的集合拆分成n多个小的 HashTable集合,默认初始化16个小的HashTable集合。

        如果同时16个线程 最终计算index值 落地到不同的小的HashTable集合 不会发生锁的竞争,同时可以支持16个线程 访问ConcurrentHashMap 写的操作,效率非常高。

        ConcurrentHashMap 1.7版本需要计算出2次 index值。

        第一次计算index= 计算key存放到具体小的HashTable

        第二次计算index= 计算key存放到具体小的HashTable,对应具体 数组 index位置。

        HashTable----数组+链表实现

### Java `ConcurrentHashMap` 使用与特性 #### 特性概述 `ConcurrentHashMap` 是线程安全的哈希表实现,在高并发环境下提供了高效的读写性能。不同于传统的同步集合类通过锁定整个容器来保证线程安全性,`ConcurrentHashMap` 只对桶(bucket)级别的数据加锁,从而允许多个线程并行访问不同部分的数据[^1]。 #### 基本用法示例 创建和初始化一个简单的 `ConcurrentHashMap`: ```java import java.util.concurrent.ConcurrentHashMap; // 创建一个新的 ConcurrentHashMap 实例 ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("one", 1); map.put("two", 2); System.out.println(map.get("one")); // 输出: 1 ``` #### 批量操作支持 正如提到的那样,当应用于 `Collection` 视图时,批量操作 (`containsAll`, `removeAll`, 和 `retainAll`) 非常有效。对于 `ConcurrentHashMap` 来说,可以利用其 keySet() 或 entrySet() 方法获取相应的视图来进行这些操作: ```java ConcurrentHashMap<Integer, String> m1 = new ConcurrentHashMap<>(); m1.put(1, "a"); m1.put(2, "b"); ConcurrentHashMap<Integer, String> m2 = new ConcurrentHashMap<>(); m2.put(2, "b"); m2.put(3, "c"); boolean isSubMap = m1.entrySet().containsAll(m2.entrySet()); System.out.println(isSubMap); // false ``` #### 并发更新处理 为了更好地适应多线程环境下的原子性需求,`ConcurrentHashMap` 提供了一些实用的方法用于执行条件性的更新动作而不必担心竞态条件的发生: - `putIfAbsent(K,V)` : 如果指定键不存在,则将其关联到给定值。 - `replace(K,V,V)` :仅当当前映射存在且等于预期旧值时替换为新值。 - `computeIfPresent/K computeIfAbsent/...`: 更灵活地基于现有条目的状态计算新的映射关系。 ```java String oldValue = map.replace("key", "oldValue", "newValue"); if (oldValue != null) { System.out.println("Replaced successfully."); } else { System.out.println("Replacement failed or no such element."); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr_GGI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值