JDK5.0以后提供了多种并发类容器来替代同步类容器,从而改善性能;
同步类容器的状态都是串行化的,如有大量请求访问应用服务,如果使用同步类容器或者是synchronized、或者是Object锁的方式,同一时间只有一个请求会被放行执行具体的业务代码,执行后会释放锁,剩余的大量请求会出现锁竞争,谁获得就执行后续的业务处理,“锁竞争”会严重影响应用程序效率和致使CPU使用率过高。
ConcurrentMap接口下有两个重要的实现:ConcurrentHashMap和ConcurrentSkipListMap(支持并发排序功能)
ConcurrentHashMap从JDK1.5开始随java.util.concurrent包一起引入JDK中,主要为了解决HashMap线程不安全和Hashtable效率不高的问题。众所周知,HashMap在多线程编程中是线程不安全的,而Hashtable由于使用了synchronized修饰方法而导致执行效率不高;因此,在concurrent包中,实现了ConcurrentHashMap以使在多线程编程中可以使用一个高性能的线程安全HashMap方案。
而JDK1.7之前的ConcurrentHashMap使用分段锁机制实现,JDK1.8则使用数组+链表+红黑树数据结构和CAS原子操作实现ConcurrentHashMap;本文将分别介绍这两种方式的实现方案及其区别。
ConcurrentHashMap内部使用(Segment)段来表示不同的部分,每个段都是一个线程安全的HashTable,它们都有自己的锁;只要多个修改操作发生在不同的段上,就可以并发进行操作,把一个整体容器分成16个段(Segment),也就是最高支持16个线程并发修改操作;这种方式是多线程场景时减小锁的粒度从而降低锁竞争的一种解决方案。
ConcurrentHashMap内部大量使用volatile关键字声明来实现数据的线程间共享。