jdk1.8源码学习之ConcurrentHashMap

目录

jdk1.7中的实现

jdk1.8中的实现

 put方法


 

https://blog.csdn.net/e5yrt2/article/details/105249839之前这篇文章介绍了hashmap的源码,但是hashmap是线程不安全的,jdk同样提供了java.util.concurrent包下的ConcurrentHashMap来解决这个问题

jdk1.7中的实现

本文虽然主要是讲1.8中的源码实现逻辑,但是提一下1.7中的实现逻辑也方便更好的理解。

jdk1.7主要采用了分离锁的思想实现的,也就是将内部进行分段(Segment),里面则是 HashEntry 的数组,和 HashMap 类似,哈希相同的条目也是以链表形式存放,而Segment又是ReentrantLock的一种实现。

static final class Segment<K,V> extends ReentrantLock implements Serializable {
	private static final long serialVersionUID = 2249069246763182397L;
    //自旋锁最多尝试次数
	static final int MAX_SCAN_RETRIES =
	        Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
    //作用同HashMap中的HashEntry一样
	transient volatile HashEntry<K,V>[] table;
	transient int count;
	transient int modCount;
	transient int threshold;
	final float loadFactor;
}
final Segment<K,V>[] segments;

 

jdk1.8中的实现

jdk1.8中主要采用了CAS和synchronized来保证并发安全性。而整个结构与1.8中的HashMap区别不大,我这里主要说下如何实现并发安全的

 

 put方法


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; K fk; V fv;
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            // 利用CAS去进行无锁线程安全操作,如果bin是空的
            if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
                break; 
        }
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else if (onlyIfAbsent // 不加锁,进行检查
                 && fh == hash
                 && ((fk = f.key) == key || (fk != null && key.equals(fk)))
                 && (fv = f.val) != null)
            return fv;
        else {
            V oldVal = null;
            synchronized (f) {
                   // 细粒度的同步修改操作... 
                }
            }
            // Bin超过阈值,进行树化
            if (binCount != 0) {
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    addCount(1L, binCount);
    return null;
}

主要实现的步骤如下:

①使用spread方法计算出hash值

②判断tab是否为空决定是否需要初始化

③定位Node,如为空则利用CAS写入数据

④不满足上述则利用synchronized写入数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值