一、简介
两种降低锁粒度的技术:
- 锁分解(将一个锁分解为两个锁)
- 锁分段(把一个锁分解为多个锁)
LinkedBlockingQueue
:先进先出,阻塞队列。拥有takeLock
和putLock
两个锁。
二、源码分析
(1)put(E)
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
// 是否已满
while (count.get() == capacity) {
// 加入 Condition 队列,等待
notFull.await();
}
// 入队
enqueue(node);
// 自增,这里用 AtomicInteger,是因为有两个锁
c = count.getAndIncrement();
// 是否满
if (c + 1 < capacity)
notFull.signal(); // 唤醒 notFull Condition队列
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty(); // 锁 takeLock,唤醒 notEmpty Condition队列
}
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
(2)take()
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
// 是否有值
while (count.get() == 0) {
notEmpty.await();
}
// 出队
x = dequeue();
// 自减
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal(); // 唤醒 notEmpty Condition 队列
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
三、应用场景
Logger
Executors