HashMap、Hashtable、ConcurrentHashMap的区别

1.HashMap与Hashtable基本上等价,区别在于Hashtable的大部分方法都是被synchronized修饰,并且键值都不能为null(HashMap则可以);
2.由于Hashtable大部分方法被synchronized修饰,因此是线程安全的,HashMap则是非线程安全的,大量的线程存取可能会出现异常;
3.hashMap效率相对比Hashtable高,因为synchronized修饰方法,获取锁会耗费时间,导致效率相对较低。

HashMap在jdk 1.7和jdk 1.8的版本在设计思想上有所改变,1.7主要是数据+链表,1.8是数组+链表+红黑树,红黑树也是一种链表数据结构。红黑树具有二叉树的优势,在查找方面具有一定优势,弥补jdk 1.7中HashMap因数据量较大导致链表过长、查询缓慢的问题。

为什么HashMap 的键值则都可以为 null?

1 static final int hash(Object key) {
2     int h;
3     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
4 }

当key为空时,哈希时会直接被赋值为0。

HashMap属性说明

 1     // 初始化容量大小
 2     static final int DEFAULT_INITIAL_CAPACITY = 16;
 3     //默认的加载因子
 4     static final float DEFAULT_LOAD_FACTOR = 0.75F;
 5     //table:数据存储区
 6     transient HashMap.Entry<K, V>[] table;
 7     //已存数据的大小
 8     transient int size;
 9     //table数组需要扩容的临界值,等于table的长度*loadFactor
10     int threshold;
11     //装载因子
12     final float loadFactor;
13     //table结构修改的次数
14     transient int modCount;

Hashtable

Hashtable为什么不允许键值为null?

 1 public synchronized V put(K key, V value) {
 2         // 确保value不为空。这句代码过滤掉了所有value为null的键值对
 3         if (value == null) {
 4             throw new NullPointerException();
 5         }
 6         // Makes sure the key is not already in the hashtable.
 7         Entry<?,?> tab[] = table;
 8         //在此处计算key的hash值,如果此处key为null,则直接抛出空指针异常。
 9         int hash = key.hashCode();
10         int index = (hash & 0x7FFFFFFF) % tab.length;
11         @SuppressWarnings("unchecked")
12         Entry<K,V> entry = (Entry<K,V>)tab[index];
13         for(; entry != null ; entry = entry.next) {
14             if ((entry.hash == hash) && entry.key.equals(key)) {
15                 V old = entry.value;
16                 entry.value = value;
17                 return old;
18             }
19         }
20         addEntry(hash, key, value, index);
21         return null;
22     }

Hashtable为什么安全

hashtable的大部分方法都是由关键字synchronized修饰,因此是线程安全的

ConcurrentHashMap

ConcurrentHashMap底层基于什么?

ConcurrentHashMap底层是基于数组+链表,而在jdk1.7和jdk1.8中稍有不同,jdk1.7中的数据结构采用分段式设计,segment数组 + HashEntry数组 + 链表实现,hash冲突采用拉链法处理。而在jdk1.8中,借鉴了jdk1.8中HashMap的设计思想,采用数组 + 链表 + 红黑树的数据结构,并且有原来的分段式锁换成了CAS + Synchronized锁,其它的地方并没有改变。

如何保证HashMap线程安全

1 1.使用Collections.synchronizedMap(Map)创建线程安全的map集合;
2 2.使用Hashtable替代hashMap;
3 3.使用ConcurrentHashMap来代替hashMap;

 

posted @ 2021-11-30 17:56  蹉~跎  阅读(100)  评论(0)    收藏  举报