hashMap 1.7底层:数组+链表 采用头插法 (当多个key发生hash冲突,就会让链表过长,查询效率较低,时间复杂度为O(n))
hashMap 1.8底层 :数组+链表+红黑树 采用尾插法 当数组容量>=64且链表长度>8 就会转换为红黑树 时间复杂度为log(On)
hashMap 允许key设置null
无论是1.7版本还是1.8版本 都会产生线程安全问题
在多线程情况下 同时操作 使用put方法
会共享同一个table数组 发生线程安全问题
hashTable 在put方法 上加了sync锁(锁住的是整个对象或者说是整个table数组),当多个线程访问put方法,是需要进行锁的竞争 锁的粒度较大 只能等到put释放 才能get,继续抢锁 ,get是不会出现线程安全问题,但是期间只能阻塞等待
hashTable 无法将key 设置null
concurrentHashMap 1.7底层
数据结构:数组+Segments分段锁(相当于多个hashTable)+HashEntry链表实现
锁的实现:Lock锁+CAS锁+UNSAFE类
分段锁设计:将大的hashTable 集合拆分成n个小的HashTable 集合 默认分成16个Segments
核心思想:减少多个线程锁的竞争,不会在访问到同一个hashTable
当多个线程进行put操作 会根据key计算具体存放hashTable的位置(如果计算的hashTable 位置不一致 则不会发生锁的竞争)如果计算hashTable位置一致 则会发生锁的竞争
计算hashTable 公式 key.hashCode()%HashTable.size
concurrentHashMap 1.8 底层
数据结构:Node数组
数组+链表+红黑树
锁的实现: 取消了Segments分段设计
index 没有发生冲突使用CAS锁
index发生冲突使用Sync锁
concurrentHashMap get方法是没有加锁的
手写concurrentHashMap 底层源码
public class ConcurrentHashMapDemo<K,V> {
/*由16个hashTable组成*/
private Hashtable[] hashtable;
public ConcurrentHashMapDemo() {
hashtable=new Hashtable[16];
for (int i = 0; i < hashtable.length; i++) {
//每个hashTable 位置new 小的hashTable
hashtable[i]=new Hashtable();
}
}
public void put(K k,V v){
//计算出key值存放的hashTable中的位置
int hashTableIndex = k.hashCode() % hashtable.length;
//将key存入计算出索引位置的小hashTable中即可
hashtable[hashTableIndex].put(k, v);
}
public V get(K k){
int hashTableIndex = k.hashCode() % hashtable.length;
return (V) hashtable[hashTableIndex].get(k);
}
public static void main(String[] args) {
ConcurrentHashMapDemo<String, String> concurrentHashMap = new ConcurrentHashMapDemo<>();
concurrentHashMap.put("lcc", "123");
concurrentHashMap.put("xxoo", "33");
concurrentHashMap.put("ooxx", "3");
System.out.println(concurrentHashMap.get("lcc"));
System.out.println(concurrentHashMap.get("xxoo"));
System.out.println(concurrentHashMap.get("ooxx"));
}
}