`
mooncui
  • 浏览: 71222 次
社区版块
存档分类
最新评论

ConcurrentHashMap, Hashtable and HashMap

    博客分类:
  • Java
阅读更多
1.
default initial capacity, HashMap is 16, Hashtable is 11(eleven).
而且HashMap的capacity应该是2的指数倍的,它还有MAXIMUM_CAPACITY。
HashMap的构造函数中还会调用一个init()方法,这个默认是空的,是留给子类来做个性化定义的。
DEFAULT_LOAD_FACTOR is 0.75f for these two.
ConcurrentHashMap的capacity方面设置和HashMap类似。
AbstractConcurrentReadCache也是map类的,默认capacity是16,最大值是1<<30, 默认factor 0.75。

2.
它们其实都是维护一个数组,数组中每个元素是一个单向链表。根据hashCode然后计算出数组中的index。
取index的算法不同:
HashMap,ConcurrentHashMap:
h & (length-1);  //这里h是改进后的hashCode,
// Entry 的hashCode:
return (key==NULL_KEY ? 0 : key.hashCode()) ^
       (value==null   ? 0 : value.hashCode());

static int hash(Object x) {
        int h = x.hashCode();

        h += ~(h << 9);
        h ^=  (h >>> 14);
        h +=  (h << 4);
        h ^=  (h >>> 10);
        return h;
    }//谁能告诉我这里怎么理解?这个算法?
                
Hashtable:
int index = (hash & 0x7FFFFFFF) % tab.length;    //length默认是11,是个质数,所以是有意义的

ConcurrentHashMap计算index的方法是和HashMap一样的


3.对于拷贝构造函数:
public HashMap(Map<? extends K, ? extends V> m) {
  this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
  putAllForCreate(m);
}
public Hashtable(Map<? extends K, ? extends V> t) {
  this(Math.max(2*t.size(), 11), 0.75f);  //为什么是2倍呢,不是t.size()/0.75?
  putAll(t);
}

public ConcurrentHashMap(Map<? extends K, ? extends V> t) {
  this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1,11),
      DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
  putAll(t);
}

4.最重要的是并发啊
HashMap没有做任何并发
Hashtable是在接口一级用synchronized实现互斥的,例如size(), isEmpty(),put,putAll(),get(key),containsKey,contains,toString,remove,clone(),writeObject 都有synchronized关键字修饰的。包括读,写操作,因为防止读不一致。
Hashtable中的每次put操作,还要检查是否容量超出范围,如果是,则要rehash

ConcurrentHashMap是引入了Segment,每个Segment有是一个hashtable,相当于是两级Hash表,然后锁是在Segment一级进行的,提高了并发性。
final Segment<K,V> segmentFor(int hash) {
  return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask];
}
ConcurrentHashMap 中的Segment中:
read不加锁,只有在读到null的情况(一般不会有null的,只有在其他线程操作Map的时候,所以就用锁来等他操作完)下调用了readValueUnderLock,这里面用到了锁。
write(包括replace,put,remove) 操作加锁

但rehash()方法不加锁
??remove方法中不是用一般的链表的remove的方法,而是将要删除的节点(e)之前的node全部复制到e的后面

abcdefghi=> edcbafghi=>然后以d为头付给tab[index]
这个的目的就是,在操作过程中不去改next指针,所以都是从链表头来进行操作,包括put也是,只能put到链表的头。
为什么这样呢,再来看一下HashEntry的定义,其他都是final的,只有value不是,它是volatile的,所以next是不能改的。
   static final class HashEntry<K,V> {  
        final K key;  
        final int hash;  
        volatile V value;  
        final HashEntry<K,V> next;  
   } 
final定义使得在构造函数执行过程中,内存分配好后,一定要先赋值后才会把指针引用到,那么其他线程看到这个对象的时候,这个值一定会有的,而value就不一定了,所以才有用个readValueUnderLock方法做备份的做法。
另外volatile关键字还保证读线程一定会等写线程执行完了才会读到,这样一定是读到最新的数据的。这样实现了read操作不需要锁。

这样计算整个map的size的消耗就比较大了,先按乐观的情况把各个Segment的country进行合计,同时看这个过程中是否有其他线程在进行修改操作,如果有,得依次把所有Segments都锁上,然后得到各个Segment的count后再依次解开各个Segment的锁.
要我说也没必要那么accurate,因为即使返回的size是accurate,但也许下一秒又变了,得到size值的代码如果想用原来那个size进行什么计算根本就是有问题的,应该要有概念这个size随时在变的,不要想非常准确,只是一个大概准确的数字就好了。

为了确保读操作能够看到最新的值,将value设置成volatile,这避免了加锁。
volatile,据说是变量会放到主存中,不是在工作内存,达到变量共享。
(相当于全局变量?)
这里还有 volatile这个关键字的含义的问题留着。


转:”按照 JLS 的说法,"在没有显式同步的情况下,一个实现可以自由地更新主存,更新时所采取的顺序可能是出人意料的。"
其意思是说,如果没有同步的话,在一个给定线程中某种顺序的写操作对于另外一个不同的线程来说可能呈现出不同的顺序, 并且对内存变量的更新从一个线程传播到另外一个线程的时间是不可预测的。
同步提供三个独立的功能――原子性、可见性和顺序性。“

参见:
http://www.iteye.com/topic/344876
http://www.iteye.com/topic/333669

5.
in Hashtable,ConcurrentHashMap: key 和value都不可为null
in HashMap, 对key,null 用new Object()来代替,其Entry.hashCode=0,而且在取出的时候还会还回null的。

6.在Hashtable中看inner class
outer class中有个变量,在inner class中需要而且因为是相同的可以直接使用,但为了在inner class中引用outer class是不好的
宁愿重复放一个拷贝属性在inner class中,avoid needing links to outer object.

7.小技巧
对于下面的定义
private <T> Enumeration<T> getEnumeration(int type) {
  if (count == 0) {
    return (Enumeration<T>)emptyEnumerator;    //这里可以看到EmptyEnumerator的用处了
  } else {
    return new Enumerator<T>(type, false);
  }
}
用这种方式调用
this.<K>getEnumeration(KEYS);

一个静态方法来构造一个同步的Set
Collections.synchronizedSet(new KeySet(), this);
分享到:
评论
5 楼 dotjar 2014-11-13  
dotjar 写道
http://burtleburtle.net/bob/hash/evahash.html
http://wangjunle23.blog.163.com/blog/static/11783817120138863910800/
mooncui 写道
haoooooj 写道
2年零3个月后,偶然路经此处,作答:

static int hash(Object x) {
        int h = x.hashCode();

        h += ~(h << 9);
        h ^=  (h >>> 14);
        h +=  (h << 4);
        h ^=  (h >>> 10);
        return h;
    }//谁能告诉我这里怎么理解?这个算法?


将10进制转换成2进制进行位移,取反,异或,运算,最后得到的是该对象的hash值。


兄台,我问的是算法,不是符号。
4 楼 dotjar 2014-11-13  
http://burtleburtle.net/bob/hash/evahash.html
mooncui 写道
haoooooj 写道
2年零3个月后,偶然路经此处,作答:

static int hash(Object x) {
        int h = x.hashCode();

        h += ~(h << 9);
        h ^=  (h >>> 14);
        h +=  (h << 4);
        h ^=  (h >>> 10);
        return h;
    }//谁能告诉我这里怎么理解?这个算法?


将10进制转换成2进制进行位移,取反,异或,运算,最后得到的是该对象的hash值。


兄台,我问的是算法,不是符号。
3 楼 ldw1986hf123 2013-12-03  
[u][/u]
2 楼 mooncui 2011-08-29  
haoooooj 写道
2年零3个月后,偶然路经此处,作答:

static int hash(Object x) {
        int h = x.hashCode();

        h += ~(h << 9);
        h ^=  (h >>> 14);
        h +=  (h << 4);
        h ^=  (h >>> 10);
        return h;
    }//谁能告诉我这里怎么理解?这个算法?


将10进制转换成2进制进行位移,取反,异或,运算,最后得到的是该对象的hash值。


兄台,我问的是算法,不是符号。
1 楼 haoooooj 2011-08-10  
2年零3个月后,偶然路经此处,作答:

static int hash(Object x) {
        int h = x.hashCode();

        h += ~(h << 9);
        h ^=  (h >>> 14);
        h +=  (h << 4);
        h ^=  (h >>> 10);
        return h;
    }//谁能告诉我这里怎么理解?这个算法?


将10进制转换成2进制进行位移,取反,异或,运算,最后得到的是该对象的hash值。

相关推荐

    hashmap和hashtable的区别.docx

    hashmap和hashtable的区别 HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。...Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

    HashMap,HashTable,ConcurrentHashMap之关联.docx

    HashMap,HashTable,ConcurrentHashMap之关联.docx

    HashMap-面试必过

    1.说一下 HashMap 的实现原理? 2.HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底层实现? 3.HashMap的put方法的具体流程? 4.HashMap的扩容操作是怎么实现的?...18.ConcurrentHashMap 和 Hashtable 的区别?

    Java集合框架完整说明便于了解集合

    HashMap 和 Hashtable 的区别,HashSet如何检查重复,HashMap的底层实现,HashMap 多线程操作导致死循环问题,ConcurrentHashMap 和 Hashtable 的区别,ConcurrentHashMap线程安全的具体实现⽅式/底层具体实现,...

    java7hashmap源码-AndroidOffer:只为帮助您获得更好的报价

    对比:Hashtable、HashMap、LinkedHashMap、ConcurrentHashMap、TreeMap (看第六条就可以) HashMap 用什么数据结构实现的 加载因子是什么 HashMap 初始化传入的容量参数的值是就是 HashMap 实际分配的空间么 ...

    Java面试考题锦集之Java基础

    这篇文章记录在准备Java后端面试复习过程中网上常见的考题,同时也会标明题目出现频率...Java Map高频hashtable和hashmap的区别及实现原理,请你说明HashMap和Hashtable的区别?HashMap 和 ConcurrentHashMap?如何使Has

    java7hashmap源码-learning-record:学习轨迹记录

    HashTable和HashMap的区别详解 LeetCode 27. 删除元素(Remove Element) 7月8号 7月5号 复习hashMap concurrentHashmap [LeetCode 70. 爬楼梯(Climbing Stairs).md](Java基础/数据结构与算法/LeetCode/LeetCode ...

    JavaSE基础面试题.docx

    17.HashMap、Hashtable、ConcurrentHashMap底层实现原理及区别 18.HashMap底层数据结构 19.说说HashMap如何处理碰撞的,或者说说它的扩容? 20.jdk7/8中对HashMap做了哪些改变? 21.负载因子为什么会影响HashMap性能...

    Java集合教程吐血整理干货.md

    HashTable的特点 TreeMap ArrayList的特点 Vector的特点 LinkedList的特点 Set ConcurrentModificationException异常 线程安全的集合 线程安全的 List CopyOnWriteArrayList 线程安全的Set 线程安全的Map ...

    Java面试题-并发.docx

    特别强调了Hashtable不允许插入null的原因,以及ConcurrentHashMap在线程安全实现和锁优化方面的策略。 总的来说,这份文档对HashMap的各个方面进行了全面而详细的阐述,既适合作为面试准备的参考资料,也适用于...

    Java面试题-哈希.docx

    特别强调了Hashtable不允许插入null的原因,以及ConcurrentHashMap在线程安全实现和锁优化方面的策略。 总的来说,这份文件对HashMap的各个方面进行了全面而详细的阐述,既适合作为面试准备的参考资料,也适用于...

    java8源码-putaoo.github.io:putao.github.io

    区别、HashMap的底层实现、HashMap 和 Hashtable 的区别、HashMap 的长度为什么是2的幂次方、HashSet 和 HashMap 区别、ConcurrentHashMap 和 Hashtable 的区别、ConcurrentHashMap线程安全的具体实现方式/底层具体...

    java8源码-java-start::seedling::seedling::seedling:学习Java语法过程中的一些案例

    区别、HashMap的底层实现、HashMap 和 Hashtable 的区别、HashMap 的长度为什么是2的幂次方、HashSet 和 HashMap 区别、ConcurrentHashMap 和 Hashtable 的区别、ConcurrentHashMap线程安全的具体实现方式/底层具体...

    【面试系列】并发容器之ConcurrentHashMap

    看你简历里写了 HashMap,那你说说它存在什么缺点? 线程不安全 迭代时无法修改值 那你有用过线程安全的 Map 吗? 有,回答在哪用过。 没有,不过我了解过。 那你说说它们的实现。 Hashtable Hashtable 本身比较低效...

    java7hashmap源码-to-be-architect:成为Java架构师,你应该学习这些

    java7 hashmap源码 to-be-architect to be a Java ...Map:ConcurrentHashMap、HashMap、HashTable 并发List Set:CopyOnWriteArrayList、CopyOnWriteArraySet、 ArrayList、 LinkedList Concurrent

    Java后端面试问题整理.docx

    • 熟悉常用集合数据结构(数组、Hashmap、ConcurrentHashMap、HashTable、ArrayList、Vetor、LinkedList、HashSet、TreeSet、LinkedHashSet),了解AVL、RBtree、B/B+树、跳表 • 熟悉常见异常分类以及处理,熟悉反射...

    袋鼠云面试(凉)

    电话面(凉) ...因为前面提了hashmap是线程不安全的容器,如果要使用线程安全的map 推荐使用 concurrentHashMap 然后问了这个问题 根据 hashtable的底层用synchronized关键字修饰的方法,和 collec

    java8源码-JavaRobot:Java学习笔记,JavaLearningNote

    ConcurrentHashMap TreeMap Hashtable Set源码系列 HashSet LinkedHashSet TreeSet HashSet Concurrent源码系列 待完善 JVM(Java虚拟机) 类加载 垃圾回收算法 JavaConcurrent(Java并发系列) 【Java并发系列】

    01java基础-集合知识点详解.xlsx

    就是一些通用java集合知识点整理,ArrayList LinkedList,HashMap,HashTable ,ConcurrentHashMap,HashSet,LinkedHashSet类通过线程安全否: 底层: 初始值: 扩容 : 区别(对比优势) 图解

    sesvc.exe 阿萨德

    本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 HashMap,没有它就不会有后面的 ConcurrentHashMap。 HashMap 众所周知 HashMap 底层是基于 数组 + 链表 组成的,不过在 jdk...

Global site tag (gtag.js) - Google Analytics