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(); //释放锁
                }
     
    结论图:
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    java 反射 报错:Attempt to get java.lang.Integer field "..." with illegal data type conversion to int
    经常报错:Communications link failure
    解析Excel
    spring+atomikos+mybatis 多数据源事务(动态切换)
    mysql 存储过程
    Ace Admin 学习笔记
    spring mvc 表单提交 乱码
    spring 事务
    基于注解的Spring多数据源配置和使用(非事务)
    javaEE版本的eclipse中导入工程,发现server里面找不到工程,根本发布不了也不能运行
  • 原文地址:https://www.cnblogs.com/liuyongcn/p/4232353.html
Copyright © 2011-2022 走看看