并发容器及原理分析
-- 1、KV集合HashMap的实现原理
1、HashMap的数据结构
2、HashMap的存取实现
什么是HashMap
HashMap是存储Key-Value键值对的集合
回忆一下SynchronousQueue在线程池的用途和场景
HashMap数据结构
table
Node节点数组
entrySet
HashMap.Node的Set集合
size
HashMap集合中元素的个数
modCount
标记HashMap修改的次数,每次调用put和clear方法,modCount会增加
threshold
当size大于threshold,就需要扩容,threshold默认为数组长度*loadFactor
loadFactor
加载因子,默认是0.75
HashMap.Node数据结构
hash
key.hashCode()经过移位计算后得到的值
key
HashMap要存储的键,通过key来获取值
Value
HashMap要存储的值
next
指向下一个Node节点
HashMap数据结构
HashMap存取实现
思考
请阅读HashMap的源码,看resize()方法是怎么实现的?
-- 2、HashMap在高并发场景下死循环分析
1、HashMap的扩容过程
2、并发情况下HashMap为什么会出现死循环问题
HashMap put过程
HashMap扩容过程
/**
* Transfers all entries from current table to newTable.
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
JDK7扩容实现
HashMap在无并发场景下扩容
注:JDK7实现
HashMap在并发场景下扩容
线程一在transfer()中的这行代码被挂起
Entry<K,V> next = e.next;
线程二在线程一挂起后执行完自己的transfer()流程
HashMap读请求获取keyHash=9数据
思考
HashMap在并发场景下除了发生死循环,还会有哪些问题发生?
-- 3、ConcurrentHashMap的高并发实现原理
1、ConcurrentHashMap的数据结构
2、ConcurrentHashMap的并发处理思路
ConcurrentHashMap 数据结构
Segment类分析
- Segment集成ReentrantLock,具有加锁解锁的功能,segments有多少个元素,说明就有多少把锁,扮演了分段锁,降低并发竞争度
- 只有写才会对对应的Segment加锁,读不加锁
思考
ConcurrentHashMap中多出Unsafe类来获取对应字段值,这样的好处是什么?
-- 4、CopyOnWriteArrayList如何实现线程安全
1、为什么需要CopyOnWriteArrayList?
2、CopyOnWriteArrayList的线程安全实现
3、CopyOnWriteArrayList的使用场景
注:
回忆一下SynchronousQueue在线程池的用途和场景
为什么需要CopyOnWriteArrayList?
运行后输出报错信息:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
阅读源码发现:
ArrayList当读写线程同时运行时,使用fast-fail机制,抛出ConcurrentModificationException异常
ArrayList在读写线程同时运行时,无法满足开发者需求
改用CopyOnWriteArrayList后:
读写同时进行时,不会抛出ConcurrentModificationException异常
CopyOnWriteArrayList实现原理
添加元素
遍历元素
取元素
CopyOnWriteArrayList优缺点分析
优点
线程安全,可以兼容读写并发
缺点
耗内存(写时复制)
数据实时性不高,可能获取到旧数据
CopyOnWriteArrayList使用场景
读多写少,如白名单黑名单等
集合数量不大
数据要求不是强实时