1、锁结构:1.7采用的是segment + HashEntry数组实现的。Segment是Reentrant的子类,其内部维护了一个Entry数组,其结构和HashMap中的Entry数组是一样的,所以说Segment其实是一个锁,可以锁住一段哈希表结构。而ConcurrentHashMap中维护了一个Segment数组,所以是基于分段锁实现的。 而JDK1.8中,ConcurrentHashMap摒弃了Segment,采用synchronized+CAS+红黑树来实现的。锁的力度也从段锁缩小为结点锁。
2、put()的执行流程有所不同。1.7中 要进行两次定位,先对Segment进行定位,在对内部数组进行定位。定位后采用 自旋锁+锁膨胀的机制进行加锁,也就是自旋获取锁,当自旋超过一定次数,会发生膨胀,直接陷入阻塞状态,等待唤醒,而且在整个put操作期间都持有锁。
3、计算size的方法不一样:1.7中会尝试不加锁的情况下统计,如果前两次结果一样,直接返回。若超过三次,则对每一个Segment进行加锁后统计。1.8 会维护一个baseCount属性来记录节点数目,和一个辅助数组,每次put操作后都会CAS自增baseCount。它统计的size是有basecount和数组的值的和决定。
4、结构上引入了红黑树:降低hash冲突的场景和时间复杂度。