目录
一、传统的集合类
- Vector和Hashtable(线程安全,但性能太差)
- ArrayList和HashMap(线程不安全,但可以用Collections.synchronizedList(new ArrayList())和Collections.synchronizedMap(new HashMap<K,V>())使之变成线程安全的)
为什么HashMap线程不安全?
- ①resize扩容会导致死循环造成CPU100%
- ②put时的可见性
当一个线程get时,另一个线程put。就会导致不一致性问题
二、CurrentHashMap
1. JDK1.7中的CurrentHashMap
- 使用的是segment分段锁,每个segment独立使用的是ReentrantLock,提高并发效率
- 使用数组+链表
2. JDK1.8中的CurrentHashMap
- 采用的是synchronized+CAS
- 数据结构使用了红黑树(当拉链超过8之后,就使用红黑树)
为什么超过8使用红黑树??
- 首先,红黑树所占用的空间要比链表占用的空间更大(是链表的两倍),在链表并不太长的时候,就先采用链表
- 当超过8时(概率很小),为了保证查询的效率(红黑树是O(logn))
3. 小“bug”
CurrentHashMap在进行单一操作时(例如put、get),可以保证线程安全,但是组合操作不能保证线程安全。(发生重排序,并不是CurrentHashMap的原因)
三、CopyOnWriteArrayList
- 思想:读写操作遵守二八原则,即读的情况占大多数,那么,可以适当提升读的速度。
- 特点:读读共享,读写共享,写写互斥
- 原理:每次copy出一个新的副本,从新副本里面写,这样的话,写和读可以同时执行,只不过读不到最新的数据。
- 存在的缺点:
- 内存问题,由于写时复制,即每次写都要新建一个副本,导致内存占用大。
- 一致性问题,读取的时候写,会出现读到的是旧值,不能实时同步。