ConCurrentHashMap
ConCurrentHashMap底层是:散列表 + 红黑树,与HashMap一样
根据顶部的注释,大概意思为
支持高并发的检索和更新
线城市安全的,并且检索操作是不用加锁的
get方法非阻塞
检索出来结果是最新设置的值
一些关于同届的方法,最好是在单线程的环境下使用,不然它只满足监控或估算的目的,在项目中(多环境下)使用它是无法准确返回的
当有太多的散列碰撞,该表会动态增长
再散列(扩容)是一件非常耗费资源的操作,最好是提前计算放入容器中有多少的元素来手动初始化装载因子和初始容量
当很多的key的HashCode相等时会非常影响性能的(散列冲突),key实现Comparable接口(直接定义比较key),会好一点
实现了Map和Iterator的所有方法
ConCurrentHashMap不允许key或value为null
ConCurrentHashMap提供的方法支持批量操作
Hashtable与ConCurrentHashMap区别
- Hashtable是在每个方法上都加了Synchronized完成同步,效率低下
- ConCurrentHashMap通过在部分加锁和利用CAS算法来实现同步
CAS算法和volatile
CAS(比较与交换,Compare and swap)是一种有名的无锁算法
CAS有3个操作数
- 内存值V
- 旧的预期值A
- 要修改的新值B
当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做
- 当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值(A和内存值V相同时,将内存值B修改为B),而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败了,并可以再次尝试(否则什么都不做)
volatile经典总结:volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性
即:
保证该变量对所有现成的可见性
- 在多线程的环境下:当这个变量修改时,所有的线程都会知道该变量被修改了
不保证原子性
- 修改变量(赋值)实质上实在JVM中分了好几步,而在这几步内(从装载变量到修改),它是不安全的
可以参考以下博客
域
1 | //散列表,迭代器就是迭代它 |
构造方法
1 | //默认初始容量为16 |
put
1 | public V put(K key, V value) { |
get
不用加锁,是非阻塞的
Node节点是重写的,设置了volatile关键字修饰,致使它每次获取的都是最新设置的值
1 | public V get(Object key) { |
总结
- 在高并发环境下,统计数据(计算size等)是无意义的,因为在下一时刻size值就发生变化了
- get方法是非阻塞,无锁的。重写Node类,通过volatile修饰next来实现每次获取都是最新设置的值
- ConcurrentHashMap的key和Value都不能为null