ConcurrentHashMap

ConcurrentHashMap引入了分段锁的概念。将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。

首先先来看一些基本的属性:

//初始容量,这个值指的是table的初始容量
static final int DEFAULT_INITIAL_CAPACITY = 16;
//并发数,其实也就是Segments数组的大小,默认是16,初始化后不可以改变。
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
//负载因子,这个负载因子是给每个 Segment 内部使用的。
static final float DEFAULT_LOAD_FACTOR = 0.75f;

在ConcurrentHashMap的源码中可以看到以下属性:

  • Segment<K,V>[] 类型的segments数组
  • HashEntry<K,V>[] 类型的table数组
  • 链表结构的HashEntry<K,V>
//segments数组
 final Segment<K,V>[] segments;

//table数组
  transient volatile HashEntry<K,V>[] table;

//链表结构的HashEntry<K,V> 
    static final class HashEntry<K,V> {
        final int hash;
        final K key;
        volatile V value;
        volatile HashEntry<K,V> next;
//HashEntry的构造函数
        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
// Segment的构造函数
        Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
            this.loadFactor = lf;
            this.threshold = threshold;
            this.table = tab;
        }

根据上述源码我画出了ConcurrentHashMap的内部结构图:
在这里插入图片描述
我们还可以看到如下源码:

   static final class Segment<K,V> extends ReentrantLock implements Serializable

由此我们可以看出,Segment继承了ReentrantLock,表明每个segment都可以当做一个可重入锁。每个segment中的数据需要同步操作的话都是使用每个segment容器对象自身的锁来实现。

HashTable和ConcurrentHashMap线程安全保证机制的不同:

  • HashTable容器使用synchronized来保证线程安全,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。
  • ConcurrentHashMap允许多个修改操作并发进行,内部使用Segment来表示这些不同的部分,每个段其实就是一个小的hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

HashMap、HashTable和ConcurrentHashMap区别:

  • HashMap
    (1).线程不安全。
    (2).继承自 AbstractMap实现了 Map, Cloneable, Serializable接口。
    (3).支持序列化。
    (4).key、value都可以为null。
    (5).一次hash找到指定的key然后遍历entry链表。
  • HashTable
    (1).线程安全 (所有的方法都加了sychronized实现)。
    (2).继承自Dictionary,实现了Map、Cloneable、Java.io.Serializable接口。
    (3).不支持序列化。
    (4).key、value都不可以为null。
    (5).一次hash找到指定的key然后遍历entry链表。
  • concurrentHashMap
    (1).线程安全(使用ReenTrantLock(可重入锁) 分段锁技术实现)。
    (2).继承自AbstractMap,实现了ConcurrentMap, Serializable接口。
    (3).支持序列化。
    (4).key、value都不可以为null。
    (5).put和 get 两次Hash到达指定的HashEntry,第一次hash到达Segment,第二次到达Segment里面的table,然后在遍历HashEntry链表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值