jdk1.8 之前的数据结构:
ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结合组成。默认有16个区段。Segment 是一种可重入锁(ReentrantLock),在 ConcurrentHashMap 里扮演锁的角色;HashEntry 则用于存储键值对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组。Seqment 的结构和 HashMap 类似,是一种数组和链表结构。一个 Segment 里包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个 HashEntry 数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得与它对应的 Segment 锁.
不同线程操作不同的Segment就不会出现安全问题,性能上大提升.在jdk1.8之前,多线程操作同一个Segment不能并发,在jdk1.8优化了.

jdk1.8 之后的数据结构:
改进:没有Segment区段了,和HashMap一致了,数组+链表+红黑树 +乐观锁 + synchronized
ConcurrentHashMap数据结构与1.8中的HashMap保持一致,均为数组+链表+红黑树,是通过乐观锁+Synchroni zed来保证线程安全的.当多线程并发向同一个散列桶添加元素时。
若散列桶为空,此时触发乐观锁机制,线程会获取到桶中的版本号,在添加节点之前,判断线程中获取的版本号与桶中实际存在的版本号是否一致,若一致,则添加成功,若不一致,则让线程自旋。
若散列桶不为空,此时使用Synchronized来保证线程安全,先访问到的线程会给桶中的头节点加锁,从而保证线程安全。