并发容器之ConcurrentHashMap(1)

2021-03-19 18:02:47 浏览数 (1)

内容

SynchronizedMapHashtableConcurrentHashMap

SynchronizedMap

HashMap不是线程安全的,即在并发场景下,多个线程共享一个HashMap对象,将会出现程序紊乱。在并发场景下如果要保证一种可行的方式是使用 Collections.synchronizedMap() 方法来包装我们的 HashMap。

代码语言:javascript复制
/**
 * Collections.synchronizedMap()源码,返回一个SynchronizedMap对象
 */
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
    return new SynchronizedMap<>(m);
}


/**
 * SynchronizedMap源码
 */
private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;
        /**
         * SynchronizedMap内部依靠Map实现常见的K-V操作。
         */
        private final Map<K,V> m;     // Backing Map
        /**
         * 锁对象,用于控制SynchronizedMap内部的Map对象m的线程安全。
         */
        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;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        ······

SynchronizedMap示意图

Hashtable

与SynchronizedMap类似,Hashtable也是通过synchronized实现线程安全的,不同的是,Hashtable并没有借助内部的属性作为锁对象,而是在每个方法上加上了synchronized关键字,即Hashtable使用的锁对象是Hashtable对象本身。

代码语言:javascript复制
public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {

    /**
     * The hash table data.
     */
    private transient Entry<?,?>[] table;

    /**
     * The total number of entries in the hash table.
     */
    private transient int count;

    /**
     * The table is rehashed when its size exceeds this threshold.  (The
     * value of this field is (int)(capacity * loadFactor).)
     *
     * @serial
     */
    private int threshold;

    /**
     * Returns the number of keys in this hashtable.
     *
     * @return  the number of keys in this hashtable.
     */
    public synchronized int size() {
        return count;
    }

    /**
     * Tests if this hashtable maps no keys to values.
     *
     * @return  <code>true</code> if this hashtable maps no keys to values;
     *          <code>false</code> otherwise.
     */
    public synchronized boolean isEmpty() {
        return count == 0;
    }
    ······

ConcurrentHashMap

SynchronizedMap和Hashtable都是通过使用一个全局的锁来同步不同线程间的并发访问,因此会带来不可忽视的性能问题——锁的粒度是方法级的,因此同一个方法无法在多线程环境下并发执行。于是就有了 HashMap 的线程安全版本—— ConcurrentHashMap 的诞生。在 ConcurrentHashMap 中,无论是读操作还是写操作都能保证很高的性能:在进行读操作时(几乎)不需要加锁,而在写操作时,JDK1.7和JDK1.8分别使用了不同的方式实现了线程安全。

JDK 1.7 ConcurrentHashMap

JDK 1.8 ConcurrentHashMap

0 人点赞