Map<String,String> map = new ConcurrentHashMap<String,String>()
1.7版本
初始容量默认为16段(Segment),使用分段锁设计
不对整个Map加锁,而是为每个Segment加锁
当多个对象存入同一个Segment时,才需要互斥
最理想的状态为16个对象分别存入16个Segment,并行数量16
使用方式与HashMap无异
只有16把锁,后续扩容之后也只有16把锁,一个锁锁多个链表数组(与1.8比较)
1.8版本
CAS(ComparableAndSwap)交换算法和同步锁
CAS(ComparableAndSwap)交换算法
V:要更新的值
E:预期的值
N:新值
当V == E时,V == N
如果在修改过程中,V已经发生变化,V != E ,则取消当前赋值操作,做下一次赋值操作
多线程访问,一个线程在修改过程中,时间片没了,下一个线程也去修改完成,上一个线程分到时间片发现V已经发生变化
同步锁锁的是表头对象,拿到锁的对象要先做节点遍历。查看有没有相同的key,
相同覆盖,不同,则挂在最后一个节点的next上
每个链表的第一个都是表头,都有锁,创建新的也是会有(和1.7不同之处)
public V put(K key, V value) {
return putVal(key, value, false);//用putVal()来判断传入的值
}
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;//f为Node中的第一个数组中的对象,作为锁头的对象
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//用Cab方法去判断如果插入的为null表明里面没有值,
if (casTabAt(tab, i, null, 插入成功,为第一个,上锁,成为锁头
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
synchronized (f) {//对f上锁,插入到这个链表数组中的元素都要经过锁头f获得锁,遍历对比
if (tabAt(tab, i) == f) { 如有相同键的对象,覆盖,没有,插入到最后一个
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {//如果key相等
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;//值覆盖
break;
}
Node<K,V> pred = e;//找到最后一个
if ((e = e.next) == null) {//如果它的下一个是null
pred.next = new Node<K,V>(hash, key,//将自己的地址存到它的next中
value, null);
break;
}
}
}