HashTable和HashMap的区别是,HashTable在操做table的方法上加入synchronized关键字,使得线程安全。实现方式和HashMap相似,可是HashTable没有处理在某个槽下的值太多,链表过长的状况。java
有序,二叉搜索树,使用红黑树。使用key进行比较,或者传入的比较器。方法containsKey、get、put和remove的时间复杂度是log(n)。数组
LinkedHashMap保存了元素的插入顺序,在遍历时会遵循插入的顺序。而HashMap遍历时,顺序是按照table的顺序,依次遍历每个槽中的链表,因此顺序和插入顺序彻底不一样。 安全
LinkedHashMap在Node上加上了before
和after
属性用以构建保持原顺序的双向链表。 并发
LinkeHashMap能够设置参数,使其从插入顺序变为访问顺序。 工具
LinkedHashMap基于HashMap,它本身的任务主要是维护保持顺序的双向链表。布局
java.util.concurrent;线程
ConcurrentHashMap提供了一个高效的、线程安全的访问和更新HashMap的方式。较之HashTable,它没有提供在整个table上的锁,同步方式粒度更细。code
看网上资料,旧版本的ConcurrentHashMap采用了分段的策略进行同步。Hash步骤以下:内存
全部并发访问ConcurrentHashMap的线程会在每一个segment上同步,因此线程能够并行的访问不一样的segment,减少了同步的粒度。 rem
可是,在1.8中,使用的是sun.misc.Unsafe
工具。它的做用有:
ConcurrentHashMap对table的操做所有由sun.misc.Unsafe来完成:
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) { return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE); } static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i, Node<K,V> c, Node<K,V> v) { //c表示旧值 //v表示新值 //更新前会验证旧值是否变化,若是变化说明期间被其它线程修改,则修改失败 //外部使用该方法通常会使用一个循环,以屡次重试 return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v); } static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) { U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v); }
能够简单的理解为上述方法是原子性的,对目标数据所在的内存位置进行了加锁,整个操做过程当中,对该部份内存的读、写不会受其它线程的影响。可见,该方法的并发实现粒度更细。
还有一点须要注意,在并发操做时,可能会出现有的线程开始扩张或缩小table,可是有的线程却试图操做table的状况。由于搬迁table上元素的过程比较耗时,因此,其它线程发现该table正在重建,会先将操做table的事情日后放一放,而是转头去帮助搬迁table,等table搬迁完毕再继续本身的活。