这篇主要是学习HashMap、ConcurrentHashMap的一个总结。
HashMap:
HashMap内部采用数组结构,数组的每个位置对应一个hash值。
数组的容量初始为16,当不足时,每次翻倍。HashMap类里面定义了一个阀值,当数量大于等于阀值时(阀值=loadFactory(默认0.75)*capacity),重新建立一个数组,数组大小为原来的2倍,并且将原来的数据重新定位到新的数组里。
这样会导致原来分配的数组失效。当堆内存空间不足时或者不能满足分配要求时,垃圾收集器才会进行回收(数组分配在堆里面),进行垃圾回收在标记阶段会进行"Stop the World",所以应该尽量避免。由于数组的分配是在一
个连续的空间里,所以在初始化HashMap时候如果没有定义数组大小的时候,HashMap过大时会产生很多失效的数组,这样即使空间里有内存也会导致垃圾回收。
所以建议在定义HashMap的时候,指定一个合适的大小是很有必要的。一个指定大小需要是2的次方,如果设置这个大小为1000,则系统默认将这个大小设置为1024.
HashMap:
HashMap内部采用数组结构,数组的每个位置对应一个hash值。
数组的容量初始为16,当不足时,每次翻倍。HashMap类里面定义了一个阀值,当数量大于等于阀值时(阀值=loadFactory(默认0.75)*capacity),重新建立一个数组,数组大小为原来的2倍,并且将原来的数据重新定位到新的数组里。
这样会导致原来分配的数组失效。当堆内存空间不足时或者不能满足分配要求时,垃圾收集器才会进行回收(数组分配在堆里面),进行垃圾回收在标记阶段会进行"Stop the World",所以应该尽量避免。由于数组的分配是在一
个连续的空间里,所以在初始化HashMap时候如果没有定义数组大小的时候,HashMap过大时会产生很多失效的数组,这样即使空间里有内存也会导致垃圾回收。
所以建议在定义HashMap的时候,指定一个合适的大小是很有必要的。一个指定大小需要是2的次方,如果设置这个大小为1000,则系统默认将这个大小设置为1024.
hash冲突的时候采用链表。链表的结构是单向的,所以 插入的时候选择在头节点插入。
key,value均可为null,key为null的时候,在数组下标为0的地方插入。
加入相同的key,value会覆盖。
需要注意的是HashMap实现了Serializable,也就是所HashMap可序列化,但是对Entry[] table 这个变量是transient,也就是说这个数组不会实例化。但是HashMap有自己的writeObject()方法。
在Effective Java里作者是这样解释的:
For example, consider the case of a hash table. The physical representation is a sequence of hash buckets containing key-value entries. The bucket that an entry resides in is a function of the hash
code of its key, which is not, in general, guaranteed to be the same from JVM implementation to JVM implementation. In fact, it isn't even guaranteed to be the same from run to run. Therefore, accepting the
default serialized form for a hash table would constitute a serious bug . Serializing and deserializing the hash table could yield an object whose invariants were seriously corrupt.
HashMap非线程安全,这在一定程度上可以提高速度。对应的线程安全版本是ConcurrentHashMap。
ConcurrentHashMap:
ConcurrentHashMap与HashMap对应,从名字上看出来,是HashMap的并发版本。
需要注意的是HashMap实现了Serializable,也就是所HashMap可序列化,但是对Entry[] table 这个变量是transient,也就是说这个数组不会实例化。但是HashMap有自己的writeObject()方法。
在Effective Java里作者是这样解释的:
For example, consider the case of a hash table. The physical representation is a sequence of hash buckets containing key-value entries. The bucket that an entry resides in is a function of the hash
code of its key, which is not, in general, guaranteed to be the same from JVM implementation to JVM implementation. In fact, it isn't even guaranteed to be the same from run to run. Therefore, accepting the
default serialized form for a hash table would constitute a serious bug . Serializing and deserializing the hash table could yield an object whose invariants were seriously corrupt.
HashMap非线程安全,这在一定程度上可以提高速度。对应的线程安全版本是ConcurrentHashMap。
ConcurrentHashMap:
ConcurrentHashMap与HashMap对应,从名字上看出来,是HashMap的并发版本。
通过设置一个segment[]数组,segment这个数组是不能扩张的,可以在构造函数中指定。数组每个成员是一个HashEntry[],在HashEntry[]中同样会使用hash函数,将不同的hash值分配到不同位置,hash冲突使用链表解决。
对HashEntry[]放入数据时采用加锁的方式访问,从而实现锁的粒度分离。锁在finally块在释放,在get()方法没有加锁。
在HashEntry类中next域被设置为final,所以插入都是在头节点。进行删除一个元素的话,需要将被删除元素之前的数据复制到一个新的链表中,之后部分不改变。
在HashEntry类中next域被设置为final,所以插入都是在头节点。进行删除一个元素的话,需要将被删除元素之前的数据复制到一个新的链表中,之后部分不改变。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25956376/viewspace-2040584/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/25956376/viewspace-2040584/