浅谈ConcurrentHashMap和HashTable

前言

我们知道HashMap是线程不安全的,那么当我们要在多线程的情况下,应该怎么办呢?

在多线程场景下,我们一般采用下面的几种方式去创建线程安全的map集合

  1. 采用Collections.synchronizedMap(Map)
  2. 采用Hashtable
  3. 采用ConcurrentHashMap

通常会采用ConcurrentHashMap,因为前面两者的并发度太低了。

Collections.synchronizedMap(Map)

synchronizedMap是Collections工具类中的一个内部类。
从下面的源码中可以看出来,SynchronizedMap维护了一个Map和一个互斥锁

    private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        // Map对象
        private final Map<K,V> m;     // Backing Map
        // 互斥锁
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }
      .................
      ................
    }

可以看到有两个构造器,需要传入一个Map对象,如果没有传入互斥锁对象,那么互斥锁会赋值为this

创建好之后对map的各种操作都是带锁的,👇

        public int size() {synchronized (mutex) {return m.size();}}
        public boolean isEmpty() {synchronized (mutex) {return m.isEmpty();}}
        public boolean containsKey(Object key) {synchronized (mutex) {return m.containsKey(key);}}
        public boolean containsValue(Object value) {synchronized (mutex) {return m.containsValue(value);}}
        public V get(Object key) {synchronized (mutex) {return m.get(key);}}

所以并发度很低,每次只允许一个线程对数据进行操作

Hashtable

Hashtable和HashMap的结构差不多。
Hashtable是线程安全的原因是因为,他在操作数据的方法上都加了synchronized,同样的,这也导致他的效率非常低。

    public synchronized int size() {
        return count;
    }
    public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
      .......
      .......
    }

Hashtable和HashMap的区别

Hashtable HashMap
线程安全 线程不安全
继承Dictionary 继承AbstractMap
不允许key或者value为null 允许为null
数组默认大小为11,扩容为2*old+1 数组默认大小为16 , 扩容为2*old

其实现在多线程环境下一般也不用Hashtable,他是一个遗留类,内部实现很多没有优化

ConcurrentHashMap

一般开发中用的都是ConcurrentHashMap,并发度高,效率高。
同样的,ConcurrentHashMap的键值不允许为null
1.7的时候采用的是分段锁的方式。(给每个段(Segment)用lock锁进行保护,相对Hashtable的synchronized关键字锁粒度更细,并发度更高)
1.8的时候优化成CAS+synchronized的方式。
具体详见👇
ConcurrentHashMap源码分析

posted @ 2020-08-22 21:58  jealous-boy  阅读(88)  评论(0编辑  收藏  举报