线程安全的HashMap,ConcurrentHashMap
HashMap是线程安全的吗?
: 不是。
多线程环境下怎么使用HashMap?
: 使用HashTable、ConcurrentHashMap。。。
你还可以多说点:
1、说下HashMap数据结构:hash桶+红黑树
2、为什么HashMap不是线程安全的?
3、HashTable和ConcurrentHashMap解决线程安全的区别?
HashTable内部每个操作期间都使用sychronized这种粗粒度的锁,就是不管三七二十一,只要线程不安全的方法上加锁。HashMap.get或list.contains,可能存在大量工作:当去遍历桶或链表的时候,可能因为hashcode分散不均匀或者某些槽糕的情况下会把散列表变成线性表,在加上遍历时必须调用equals(本身存在一定的计算量),这样会花费很长一段时间,而其他线程只能等待。
ConcurrentHashMap采用了不同的加锁策略:分段锁。
顾名思义就是将一个竞争激烈的锁分解成两个或多个锁,在ConcurrentHashMap的实现中使用了一个包含16个锁的数组,每个锁保护所有散列桶的1/16,其中第N个散列通被第(N mod 16)个锁来保护。如果存在批量处理操作eg. clear 或者在扩容时需要重新计算键值的散列值要分布到更大的桶集合中去时,就需要获取所有的锁:采用递归
ConcurrentHashMap.get
public object get(Object key){
int hash = hash(key);
//分段锁,当前是第(hash% N_LOCKS)个段锁
sychronized(locks[hash% N_LOCKS]){
for(...){
if(..equals(.)){
return ...;
}
}
}
}
ConcurrentHashMap.clear
{
for(i==0){
sychronized(locks[i% N_LOCKS){
buckets[i] == null;
}
}
}
ConcurrentHashMap.size
因为size是map的热点区域,每个造成数量变化的操作都需要去修改它,就要保证size值的同步,这样就会影响分段锁的伸缩性。所以每段都各自维护了一个计数器,
总结:
分段锁机制下 任意数量的读取线程可以并发得访问Map,读线程和写线程可以并发执行,并且一定数据量的写入线程可以并发得修改Map。
这样多回答一点,让面试官对你有更高的评价!
其实如果继续说下去可能要问问一些线程安全问题了,比如线程池配置参数有哪些?线程与进程的区别?你工作中有没有用到过锁?
锁的概念还是相当广泛的,可以说方方面面都离不开它,比如事务。
推荐大家看看<Java并发编程>这本书,我最近就在学习,希望让以前浮躁的知识沉淀下。欢迎大家与我一起学习Java并发编程,讨论技术。
网友评论