• 【JAVA】ConcurrentHashMap



    HashTable 写操作时候,Lock全表 
     
    源码:
     public synchronized V put(K key, V value) {
     // Make sure the value is not null
     if (value == null) {
         throw new NullPointerException();
     }
     
     // Makes sure the key is not already in the hashtable.
     Entry tab[] = table;
     int hash = key.hashCode();
     int index = (hash & 0x7FFFFFFF) % tab.length;
     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
         if ((e.hash == hash) && e.key.equals(key)) {
      V old = e.value;
      e.value = value;
      return old;
         }
     }
     
    因为该方法是用了synchronized方法,因此,可以防止多个线程同时方法这个对象的synchronized方法
    对象中 remove,putAll,clear等常用方法都是用了synchronized 方法,因此,当一个线程调用其中的一个synchronized方法时,其他线程就不能方法对象中其中的任何一个synchronized方法。
     

    ConcurrentHashMap 允许多个修改操作并发进行
     
    ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table。
      /**
         * The segments, each of which is a specialized hash table
         */
        final Segment[] segments;
     
    一个ConcurrentHashMap中默认有16个Segment段,源码如下:
    /**
         * The default number of concurrency control segments.
         **/
        static final int DEFAULT_SEGMENTS = 16;
     
    现在看一下put 方法,源码
     public V put(K key, V value) {
            if (value == null)
                throw new NullPointerException();
            int hash = hash(key);
            return segmentFor(hash).put(key, hash, value, false);
        }
    可见方法中不支持value为null的情况,如果为空则抛出空指针异常
    操作时通过segmentFor方法得到 Segment[]中的Segment<K,V>,然后将KEY和VALUE存入segment中
    再看一下Segment<K,V>对象的put方法
     
     V put(K key, int hash, V value, boolean onlyIfAbsent) {
                lock();  //加锁
                try {
                    int c = count;
                    if (c++ > threshold) // ensure capacity
                        rehash();
                    HashEntry[] tab = table;
                    int index = hash & (tab.length - 1);
                    HashEntry<K,V> first = (HashEntry<K,V>) tab[index];
                    HashEntry<K,V> e = first;
                    while (e != null && (e.hash != hash || !key.equals(e.key)))  
                        e = e.next;  //查找到旧值
     
                    V oldValue;
                    if (e != null) {  //存在修改值
                        oldValue = e.value;
                        if (!onlyIfAbsent)
                            e.value = value;
                    }
                    else {  //不存在创建新的HashEntry保存数据
                        oldValue = null;
                        ++modCount;
                        tab[index] = new HashEntry<K,V>(key, hash, first, value);
                        count = c; // write-volatile
                    }
                    return oldValue;
                } finally {
                    unlock(); //释放锁
                }
     
    结论图:
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    kafka学习笔记(六)kafka的controller模块
    腾讯蓝鲸使用笔记
    kafka学习笔记(五)kafka的请求处理模块
    kafka学习笔记(四)kafka的日志模块
    kafka学习笔记(三)kafka的使用技巧
    kafka学习笔记(二)kafka的基本使用
    kafka学习笔记(一)消息队列和kafka入门
    大数据安全与RANGER学习和使用
    10-Linux 基本指令
    09-迭代器、模块
  • 原文地址:https://www.cnblogs.com/liuyongcn/p/4232353.html
Copyright © 2020-2023  润新知