隊列
基本介紹
隊列是一種數據結構,有點類似棧,不同的是,在隊列中第一個插入的數據會被首先移
除。
特點:先進先出
效率:和棧一樣,隊列中插入數據和移除數據元素的時間複雜度都是O(1).
隊列的使用
隊列可分爲兩種,一種是阻塞隊列,一種是非阻塞隊列。
阻塞隊列和非阻塞隊列的區別在於:阻塞隊列可以阻塞,非阻塞隊列不能阻塞(廢話)
非阻塞隊列只能使用隊列wait(),notify()進行隊列消息傳送。而阻塞隊列當隊列裏面沒
值時,會阻塞直到有值輸入。輸入也一樣,當隊列滿的時候,會阻塞,直到隊列不爲
空。
常用阻塞隊列
ArrayBlockingQueue
基於數組實現的一個阻塞隊列,在創建ArrayBlockingQueue對象使,必須制定容器量
大小。並且可以指定公平性和非公平性,默認情況下爲非公平性,即不保證等待時間最
長的隊列最優先能訪問隊列。
LinkendBlockingQueue
基於鏈表實現的一個阻塞隊列,在創建LinkedBlockingQueue對象時如果不指定容量大
小,則默認大小爲Integer.max_vakue.
PriorityBlockingQueue
它會按照元素的優先級對元素進行排序,按照優先級順序出隊,每次出隊的元素都是優
先級最高的元素。注意,此阻塞隊列爲無界隊列,即容量沒有上限。前面2個都是有界隊
列。
DelayQueue
一種延時阻塞隊列,DelayQueue中的元素只有當其指定的延遲時間到了,才能夠從隊列
中獲取到該元素。DelayQueue也是一種無界隊列,因此往隊列中插入數據的操作永遠不
會被阻塞,而只有獲取數據的消費者纔會被阻塞。
常用方法
以下五個方法,在阻塞隊列和非阻塞隊列中均可使用。對於非阻塞隊列,一般情況下建
議使用offer(),poll(),和peek()三個方法,不建議使用add()和remove()方法。因爲
使用offer,poll,和peek方法可以通過返回值判斷操作成功與否,而使用add和remove方
法達不到這樣的效果。注意,非阻塞隊列中的方法都沒進行同步措施!!!
方法名 |
方法描述 |
add(E e) |
將元素e插入到隊列末尾,如果成功返回true,如果失敗或隊列已滿則拋出異常 |
remove() |
移除隊首元素,若移除成功,則返回true.如果失敗或隊列爲空則返回false |
offer(E e) |
將元素e插入到隊列末尾,如果成功返回true, 如果失敗或隊列已滿則返回false |
poll() |
移除並獲取隊首元素,若成功則返回對首元素,否則返回null |
peek() |
獲取隊首元素,若成功則返回隊首元素,否則返回null |
阻塞隊列中常用方法
阻塞隊列包括了非阻塞隊列中的大部分方法,上面列舉的5個方法都在阻塞隊列
中存在,但是要注意5個方法在阻塞隊列中都進行了同步措施。
除此之外,阻塞隊列提供了另外4種非常有用的方法:
方法名 |
方法描述 |
put(E e) |
put方法用來向隊尾存入元素,如果隊列滿,則等待 |
take() |
tack方法用來從隊首取元素,如果隊列爲空,則等待 |
offer(E e, long timeout, TimeUnit unit) |
offer方法用來向隊尾存入數據,如果隊列滿,則等待一定的時間,當時間期限到達時,如果還沒有成功插入,則返回false;否則返回true. |
poll( long timeout, TimeUnit unit) |
poll方法用來從隊首取元素,如果隊列爲空,則等待一定的時間,當時間期限到達時,如果還沒有獲取,則返回false,否則返回true. |
阻塞隊列之生產者消費者模型
需求分析
對於生產者消費者模型,如果庫存爲0,消費者需等待,如果庫存已滿,生產者需等待。
代碼演示
public class test {
public static void main(String[] args) {
test t = new test();
Produce p = t.new Produce();
Customer c = t.new Customer();
p.start(); c.start();
}
private int queueSize = 10;
private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(queueSize);
class Produce extends Thread{
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
try {
queue.put(1);
System.out.println("向隊列中添加元素,隊列的剩餘空間爲" + (queueSize-queue.size()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Customer extends Thread{
@Override
public void run() {
consume();
}
private void consume() {
while(true) {
try {
queue.take();
System.out.println("從隊列中取走一個元素,隊列剩餘:" + queue.size() + "個元素");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
非阻塞隊列之生產者消費者模型
需求分析
對於生產者消費者模型,如果庫存爲0,消費者需等待,如果庫存已滿,生產者需等待。
代碼演示
public class test2 {
public static void main(String[] args) {
test2 t2 = new test2();
Producer p = t2.new Producer();
Customer c = t2.new Customer();
p.start(); c.start();
}
private int queueSize = 10;
private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
class Producer extends Thread {
@Override
public void run() {
produce();
}
private void produce() {
while(true) {
synchronized(queue) {
while(queue.size() == queueSize) {
System.out.println("隊列已滿,需要等待");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offer(1);
System.out.println("向隊列中插入了一個數據,隊列剩餘空間" + (queueSize - queue.size()));
queue.notify();
}
}
}
}
class Customer extends Thread {
@Override
public void run() {
consume();
}
private void consume() {
while(true) {
synchronized(queue) {
while(queue.size() == 0) {
try {
System.out.println("隊列已空,等待數據");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll();
System.out.println("從隊列中取走一個元素,隊列剩餘:" + queue.size() + "個元素");
queue.notify();
}
}
}
}
}
實際生產情況下使用阻塞隊列的情況居多!