持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
思考:HashTable是线程安全的,为什么不推荐使用?
HashTable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都去竞争一把锁,导致效率非常低下。
1 ConcurrentHashMap 1.7
在JDK1.7中ConcurrentHashMap采用了数组+分段锁的方式实现。
Segment(分段锁)-减少锁的粒度
ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)。
1.存储结构
Java 7 版本 ConcurrentHashMap 的存储结构如图:


ConcurrnetHashMap 由很多个 Segment 组合,而每一个 Segment 是一个类似于 HashMap 的结构,所以每一个 HashMap 的内部可以进行扩容。但是 Segment 的个数一旦初始化就不能改变,默认 Segment 的个数是 16 个,所以可以认为 ConcurrentHashMap 默认支持最多 16 个线程并发。
2. 初始化
通过 ConcurrentHashMap 的无参构造探寻 ConcurrentHashMap 的初始化流程。- /**
- * Creates a new, empty map with a default initial capacity (16),
- * load factor (0.75) and concurrencyLevel (16).
- */
- public ConcurrentHashMap() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
- }
复制代码 无参构造中调用了有参构造,传入了三个参数的默认值,他们的值是。- /**
- * 默认初始化容量,这个容量指的是Segment 的大小
- */
- static final int DEFAULT_INITIAL_CAPACITY = 16;
- /**
- * 默认负载因子
- */
- static final float DEFAULT_LOAD_FACTOR = 0.75f;
- /**
- * 默认并发级别,并发级别指的是Segment桶的个数,默认是16个并发大小
- */
- static final int DEFAULT_CONCURRENCY_LEVEL = 16;
- Segment下面entryset数组的大小是用DEFAULT_INITIAL_CAPACITY/DEFAULT_CONCURRENCY_LEVEL求出来的。
复制代码 接着看下这个有参构造函数的内部实现逻辑。
[code]@SuppressWarnings("unchecked")public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel) { // 参数校验 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel > segmentShift) & segmentMask) |