ConcurrentHashMap源码解读[面试专题](集合相关)

2022-06-14 20:49:51 浏览数 (1)

JDK1.7ConcurrentHashMap源码解读

使用传统HashTable保证线程问题,是采用synchronized锁将整个HashTable中的数组锁住, 在多个线程中只允许一个线程访问Put或者Get,效率非常低,但是能够保证线程安全问题。

Jdk官方不推荐在多线程的情况下使用HashTable或者HashMap,建议使用ConcurrentHashMap分段HashMap。 效率非常高。

ConcurrentHashMap将一个大的HashMap集合拆分成n多个不同的小的HashTable(Segment),默认的情况下是分成16个不同的 Segment。每个Segment中都有自己独立的HashEntry<K,V>[] table;

核心参数:

initialCapacity —16 初始化

loadFactor HashEntry<K,V>[] table; 加载因子0.75

concurrencyLevel 并发级别 默认是16

cas与乐观锁机制原理(简单)

一直卡死,消耗cpu资源,一直重试。

hashtable缺点

底层使用synchronized锁实现的,但是将整个数组都给锁住了。

1.7ConcurrentHashMap

将一个大的ConcurrentHashMap集合拆分成n多个不同的hashtable,在每个小的hashtable中都有自己的table【】

代码语言:javascript复制
package com.gtf.xc;

import java.util.HashMap;

public class MyConcurrentHashMap
        <K, V> {
    /**
     * segments
     */
    private HashMap<K,V>[] segments;
    public MyConcurrentHashMap() {
        segments=new HashMap[16];
        //注意是懒加载
    }
    public void put(K key, V value) {
        //第一次计算key,计算key存放在哪一个hashtable
        int segmentsIndex =key.hashCode()& (segments.length  - 1);
        HashMap<K, V> segment = segments[segmentsIndex];
        //segment == null
        if (segment == null) {
            segment=new HashMap<>();
        }
        segment.put(key,value);
        segments[segmentsIndex]=segment;
    }
    public V get(K key) {
        int segmentsIndex =key.hashCode()& (segments.length  - 1);
        HashMap<K, V> segment = segments[segmentsIndex];
        if (segment != null) {
          return  segment.get(key);
        }
        return null;
    }

    public static void main(String[] args) {
        MyConcurrentHashMap<Object, Object> objectObjectMyConcurrentHashMap = new MyConcurrentHashMap<>();
        for (int i = 0; i < 10; i  ){
            objectObjectMyConcurrentHashMap.put(i,i);
        }
       for (int i = 0; i < 10; i  ) {
           objectObjectMyConcurrentHashMap.get(i);
           System.out.println( objectObjectMyConcurrentHashMap.get(i));
       }

    }
}

没有获取到锁的线程

  1. 自旋 缓存当前对应冲突链表
  2. 每次检查 当前缓存链表头节点是否发生变化
  3. 如果发生变化的情况下 缓存最新
  4. 自旋的次数最多为64

实现原理

  • 由多个不同的sement对象组成
  • 使用 luck锁 cas
  • unsafe 直接查询主内存最新的数据
  • 使用cas做修改

JDK1.8ConcurrentHashMap

ConcurrentHashMap1.8的取出取消segment分段设计,采用对CAS synchronized保证并发线程安全问题,将锁的粒度拆分到每个index 下标位置,实现的效率与ConcurrentHashMap1.7相同。

0 人点赞