集合
Vector
Vector和ArrayList类似,是长度可变的数组。
与ArrayList不同的是,Vector是线程安全的,它给几乎所有的public方法都加上了synchronized关键字。
由于加锁导致性能降低,在不需要并发访问同一对象时,这种强制性的同步机制就显得多余。
HashTable
数组+链表。
给几乎所有public方法都加上了synchronized关键字。
ConcurrentHashMap
HashTable的加锁方法是给每个方法加上synchronized关键字,这样锁住的是整个Table对象。
而ConcurrentHashMap是更细粒度的加锁。
在JDK1.8之前,ConcurrentHashMap加的是分段锁,也就是Segment锁,每个Segment含有整个table的一部分,这样不同分段之间的并发操作就互不影响。
JDK1.8对此做了进一步的改进,它取消了Segment字段,直接在table元素上加锁,实现对每一行进行加锁,进一步减小了并发冲突的概率
CopyOnWriteArrayList和CopyOnWriteArraySet
它们是加了写锁的ArrayList和ArraySet,锁住的是整个对象,但读操作可以并发执行。
Collections的synchronizedXXX()方法
将线程不安全的集合转化为线程安全的。
Collections针对每种集合都声明了一个线程安全的包装类,在原集合的基础上添加了锁对象,集合中的每个方法都通过这个锁对象实现同步
锁
synchronized(悲观锁)
CAS(乐观锁)
Compare And Swap。
CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。
更新一个变量的时候:
- 变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
- 变量的预期值A和内存地址V当中的实际值不同时,提交失败,重新获取内存地址V的当前值,并重新计算想要修改的新值。
Atomic开头的包装类
比如,AtomicBoolean,AtomicInteger,AtomicLong。它们分别用于Boolean,Integer,Long类型的原子性操作。
Atomic操作的底层实现正是利用的CAS机制。
ReentrantLock
- ReentrantLock是JDK方法,需要手动声明上锁和释放锁,因此语法相对复杂些;如果忘记释放锁容易导致死锁
- ReentrantLock具有更好的细粒度,可以在ReentrantLock里面设置内部Condititon类,可以实现分组唤醒需要唤醒的线程
- RenentrantLock能实现公平锁。
FIFO同步队列实现,阻塞线程。
ReentrantLock reentrantLock = new ReentrantLock(true);
java util concurrent
创建 java.util.concurrent 的目的就是要实现 Collection 框架对数据结构所执行的并发操作。
