并发容器基础
LinkedBlockingQueue
线程安全:独占锁(阻塞队列)
容量:0x7ffffffff,可指定容量,可以说是有界阻塞队列
数据结构:单向链表
实现:
2*Node 队列头、队列尾
2*Lock 出队、入队锁
count(AtomicInteger) 元素个数
notEmpty、notFull 出队、入队操作线程等待队列
应用场景:
ArrayBlockingQueue
线程安全:独占锁(阻塞队列)
数据结构:有界数组
指定容量
实现:
数组items存放元素
全局独占lock,出队,入队,获取count都是加锁操作(锁粒度大)
takeIndex、putIndex 队头指针、队尾指针
*ps:有意思的是,只靠takeIndex和putIndex来看队头和队尾,它俩之间的就是元素。比如容量为10,takeIndex = 8, putIndex = 3, 那么元素列表下标就是[8,9,0,1,2,3];
notEmpty、notFull
应用场景:
疑问:
- ArrayBlockingQueue和LinkedBlockingQueue的区别和适用场景? 为什么使用锁的方式不同,ArrayBlockingQueue要使用全局锁?使用出队、入队锁可不可以?
ConcurrentLinkedQueue
线程安全:CAS(非阻塞队列)
无界
数据结构:单向链表
实现:
由于offer、poll都是非阻塞CAS算法,并发情况下size函数并不是很有用
使用场景:
PriorityBlockingQueue
DelayQueue
CopyOnWriteArrayList
读操作无锁,写操作加锁
实现:
有个内部静态类COWSubList,是subList(int fromIndex, int toIndex)返回的结果
添加元素时,复制一个len + 1的数组,写入元素,然后替换原来的数组, setArray应该是原子的
* ps System.arrayCopy是浅拷贝
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
final void setArray(Object[] a) {
array = a;
}
使用场景:读操作很多,写操作极少的并发场景。
网友评论