标准库里面大部分的集合类,都是线程不安全的~~
少数几个线程安全的 : Vector,Stack,HashTable 虽然线程安全,但是其实不太推荐用
Collections.synchronizedList(new ArrayList);
CopyOnWriteArrayList
不加锁保证线程安全HashMap
本身不是线程安全的.
在多线程环境下使用哈希表可以使用:
只是简单的把关键方法加上了 synchronized
关键字,不推荐使用
因为最大的问题是属于Hashtable
无脑给各种方法加 synchronized
…
而加锁是需要因地制宜的,所以这种方法其实是不太合理的!
ConcurrentHashMap
背后做了很多优化策略!
优化策略:
HashTable
直接在方法上加synchronized
,相当于是对this
加锁,而this
只是针对哈希表对象来加锁,一个哈希表只有一个锁…
意味着:
多个线程,无论这些线程都是如何操作这个哈希表,都会产生锁冲突!!多个线程,无论这些线程都是如何操作的这个哈希表,都会产生锁冲突了!
而
ConcurrentHashMap
做出了改进~
ConcurrentHashMap
不是一把锁,而是多把锁 ~
给每个哈希桶都分配一把锁
此时只有当两个线程访问同一个哈希桶的时候,才有锁冲突~
如果不是同一个哈希桶,则没有锁冲突了!!
由于哈希桶个数很多~ 此时恰好两个线程操作同一个哈希桶的概率就大大降低了~~
ConcurrentHashMap
每个哈希桶都有自己的锁~
大大降低了锁冲突的概率,性能也就大大提高了!
充分的利用到了CAS
的特性
比如像维护元素个数,都是通过CAS
来实现,而不是加锁~
包括还有些地方直接使用CAS
实现的轻量级锁来实现~
虽然synchronized
内部已经有很多优化了,但是终究这里优化的是JVM
内部的~ 程序员是不可控的!
ConcurrentHashMap
思路就是能不加锁就不加~
ConcurrentHashMap 核心优化思路:进一切可能降低锁冲突的概率!!!! |
分段锁:
旧版本的ConcurrentHashMap
实现方式(从Java8就没了) ,新版本的是每个链表分一个锁,分段锁是好几个链表共用同一个锁(锁冲突概率要比每个链表一把锁更高,代码实现起来更复杂了)
HashMap
key
允许为null
,HashTable
和ConcurrentHashMap
key
不能为null