java1.7以前ConcurrentHashMap的size方法

从java1.5开始java加入了Doug Lea大神的concurrent包下的代码,看了Doug Lea的代码越看越惊心,真的是太厉害了,神一样的感觉(感叹一下)。

      进入正题,ConcurrentHashMap这个类是为了在高并发环境下而创建的代替HashMap散列结构,因此在实现了HashMap功能的基础上加入了分段锁的概念(java1.7包括1.7以前使用Segment继承ReentrantLock的方式实现),与HashTable这类容器相比提高了并发程度,同时避免了HashMap可能产生的线程不安全问题。在了解这些基础知识以后,会有一个问题,既然使用了分段锁,那整个Map的size该如何统计?是没一个segment都上锁统计么?这边先看一下源码:

java1.7以前ConcurrentHashMap的size方法_第1张图片
concurrenHashMap size方法

      发现获取全部分段锁来进行size统计是有条件,而不是一开始就进行的,是需要进行RETRIES_BEFORE_LOCK比较判断的,那我们先把这个放一放,看看如何会达成这个条件。

逻辑是这样的:

java1.7以前ConcurrentHashMap的size方法_第2张图片
获取全部分段锁进行size统计之前先尝试不加锁统计

      首先遍历HashMap中已有的segments将每个segment的count加起来作为整个hashMap的size,自然能想到那这时候有其他线程修改了segement中的数据让count有变化我怎么办?我并不知道到底有没有被修改啊。这时候不得不佩服大神的思路,他利用modCount和两次比较来实现size的确认。具体过程是:

1.进行第一遍遍历segments数组,将每个segemnt的count加起来作为总数,期间把每个segment的modCount加起来sum作为结构是否被修改的判断依据。(在HashMap也有同样的modCount这个变量,它负责记录容器中数据的变化,如每次进行put,remove,replace都会去修改这个值,而ConcurrentHashMap使用modCount和HashMap略有不同,HashMap使用modCount是为了检测一些比较明显的并发问题,而ConcurrentHashMap的modCount则主要是使用在size方法中,而并发问题通过锁来解决,使用modCount来记录每次数据变更操作,但不会像HashMap那样抛出ConcurrentModificationException异常)。

2.连续做两遍segements循环统计segment出count,拿第一次的modCount和第二次的modCount做比较,如果相同意味着在第一遍统计size期间,segments并没有被改动,即统计出的count是正确的。

3.如果经判断发现两次统计出的modCount并不一致,那很尴尬,要重新启用最早所说的全部segment加锁的方式来进行count的获取和统计了,这样在次期间每个segement都被锁住,无法进行其他操作,统计出的count自然很准确。

      之所以要先不加锁进行判断,道理很明显,就是不希望因为size操作获取这么多锁,因为获取锁不光占用资源,也会影响其他线程对ConcurrentHash的使用,影响并发情况下程序执行的效率。这个和ConcurrentHashMap创建的原因是违背的。

你可能感兴趣的:(java1.7以前ConcurrentHashMap的size方法)