1188 设计有限阻塞队列
实现一个拥有如下方法的线程安全有限阻塞队列:
BoundedBlockingQueue(int capacity) 构造方法初始化队列,其中capacity代表队列长度上限。
void enqueue(int element) 在队首增加一个element. 如果队列满,调用线程被阻塞直到队列非满。
int dequeue() 返回队尾元素并从队列中将其删除. 如果队列为空,调用线程被阻塞直到队列非空。
int size() 返回当前队列元素个数。
你的实现将会被多线程同时访问进行测试。每一个线程要么是一个只调用enqueue方法的生产者线程,要么是一个只调用dequeue方法的消费者线程。size方法将会在每一个测试用例之后进行调用。
请不要使用内置的有限阻塞队列实现,否则面试将不会通过。
示例 1:
输入:
1
1
["BoundedBlockingQueue","enqueue","dequeue","dequeue","enqueue","enqueue","enqueue","enqueue","dequeue"]
[[2],[1],[],[],[0],[2],[3],[4],[]]
输出:
[1,0,2,2]
解释:
生产者线程数目 = 1
消费者线程数目 = 1
BoundedBlockingQueue queue = new BoundedBlockingQueue(2);
queue.enqueue(1);
queue.dequeue();
queue.dequeue();
queue.enqueue(0);
queue.enqueue(2);
queue.enqueue(3);
queue.enqueue(4);
queue.dequeue();
queue.size();
示例 2:
输入:
3
4
["BoundedBlockingQueue","enqueue","enqueue","enqueue","dequeue","dequeue","dequeue","enqueue"]
[[3],[1],[0],[2],[],[],[],[3]]
输出:
[1,0,2,1]
解释:
生产者线程数目 = 3
消费者线程数目 = 4
BoundedBlockingQueue queue = new BoundedBlockingQueue(3);
queue.enqueue(1);
queue.enqueue(0);
queue.enqueue(2);
queue.dequeue();
queue.dequeue();
queue.dequeue();
queue.enqueue(3);
queue.size();
由于生产者/消费者线程的数目可能大于1,我们并不知道线程如何被操作系统调度,即使输入看上去隐含了顺序。因此任意一种输出[1,0,2]或[1,2,0]或[0,1,2]或[0,2,1]或[2,0,1]或[2,1,0]都可被接受。
方法1:Semaphore
class BoundedBlockingQueue {
private int capacity;
private Semaphore producerSema;
private Semaphore consumerSema;
private LinkedList<Integer> list = new LinkedList<>();
public BoundedBlockingQueue(int capacity) {
this.capacity = capacity;
consumerSema = new Semaphore(0);
producerSema = new Semaphore(capacity);
}
public void enqueue(int element) throws InterruptedException {
producerSema.acquire();
list.add(element);
consumerSema.release();
}
public int dequeue() throws InterruptedException {
consumerSema.acquire();
int res = list.removeFirst();
producerSema.release();
return res;
}
public int size() {
return list.size();
}
}
方法2:synchronized
class BoundedBlockingQueue {
private int capacity;
private LinkedList<Integer> list;
private Object obj = new Object();
public BoundedBlockingQueue(int capacity) {
this.capacity = capacity;
list = new LinkedList<>();
}
public void enqueue(int element) throws InterruptedException {
synchronized (obj) {
while (size() >= capacity) {
obj.wait();
}
list.add(element);
obj.notifyAll();
}
}
public int dequeue() throws InterruptedException {
int res;
synchronized (obj) {
while (size() <= 0) {
obj.wait();
}
res = list.removeFirst();
obj.notifyAll();
}
return res;
}
public int size() {
return list.size();
}
}