zoukankan      html  css  js  c++  java
  • 【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(); //释放锁
                }
     
    结论图:
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    CentOS /RHEL系统怎么更新安全补丁
    使用yum查询系统安装的软件及可以更新的软件并单独指定升级某一个软件
    惠普服务器通过ILO系统远程安装系统
    django进行数据库迁移的错误处理方法:You are trying to change the nullable field 'title' on book to non-nullable without a d
    Django数据库增删改查
    linux用户
    linux基础
    mysql小白系列_01 原理
    mysql运维入门6:MySQL读写分离
    mysql运维入门5:MySQL+kepalived高可用架构
  • 原文地址:https://www.cnblogs.com/liuyongcn/p/4232353.html
Copyright © 2011-2022 走看看