阻塞队列原理?

👌阻塞队列原理?

题目详细答案

阻塞队列是一种线程安全的队列,它在插入和删除操作上可以阻塞线程,以实现生产者-消费者模式等并发编程需求。阻塞队列的核心原理包括锁机制和条件变量。

基本原理

锁机制

阻塞队列使用锁(如ReentrantLock)来确保线程安全。锁保证了同一时间只有一个线程可以执行插入或删除操作,从而避免并发问题。

条件变量

阻塞队列使用条件变量(Condition)来管理线程的等待和通知。条件变量是与锁关联的,可以在特定条件下阻塞线程并在条件满足时唤醒线程。例如,notEmpty和notFull是常见的条件变量,分别用于表示队列是否为空和是否已满。

等待和通知机制:

当线程试图执行插入操作而队列已满时,它会在notFull条件变量上等待,直到队列中有空闲空间。

当线程试图执行删除操作而队列为空时,它会在notEmpty条件变量上等待,直到队列中有可用的元素。

当插入或删除操作成功后,相应的条件变量会被通知(唤醒),以便其他等待的线程可以继续执行。

具体实现 Demo

LinkedBlockingQueue是一个基于链表实现的可选有界阻塞队列。它的基本原理如下:

内部结构:使用一个链表来存储元素。使用两个锁:takeLock和putLock,分别用于控制删除和插入操作。使用两个条件变量:notEmpty和notFull,分别用于表示队列是否为空和是否已满。

插入操作(put)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity) {
notFull.signal();
}
} finally {
putLock.unlock();
}
if (c == 0) {
signalNotEmpty();
}
}

删除操作(take)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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();
}
} finally {
takeLock.unlock();
}
if (c == capacity) {
signalNotFull();
}
return x;
}

等待和通知

在插入操作中,如果队列已满,线程会在notFull条件变量上等待。

在删除操作中,如果队列为空,线程会在notEmpty条件变量上等待。

插入或删除操作成功后,会相应地通知等待的线程。

/rizcvgg0mxqp9iv7>

 wechat
天生我才必有用