java數據結構之隊列

隊列

基本介紹

隊列是一種數據結構,有點類似棧,不同的是,在隊列中第一個插入的數據會被首先移
除。
特點:先進先出
效率:和棧一樣,隊列中插入數據和移除數據元素的時間複雜度都是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,消費者需等待,如果庫存已滿,生產者需等待。

代碼演示

/**
 * 阻塞隊列
 * @author Mr.qian
 *
 */
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; //定義空間長度
	//ArrayBlockingQueue必須定義長度
	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;
	// PriorityQueue非阻塞隊列, PriorityBlockingQueue阻塞隊列
	private PriorityQueue<Integer> queue =  new PriorityQueue<Integer>(queueSize);
	
	
	//生產則 內部類
	//如果隊列填滿,需要wait進行等待,一旦有容量繼續生產消息,需要notify這個線程
	class Producer extends Thread {
		@Override
		public void run() {
			produce();
		}
		
		private void produce() {
			//無限制添加
			while(true) {
				//由於線程是非阻塞的,所以需要用到同步代碼塊將該線程wait(),notify()
				synchronized(queue) {
					while(queue.size() == queueSize) {
						System.out.println("隊列已滿,需要等待");
						//線程等待
						try {	
							queue.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					//非阻塞隊列用offer 加入數據
					queue.offer(1);	
					System.out.println("向隊列中插入了一個數據,隊列剩餘空間" + (queueSize - queue.size()));
					//notify() 喚醒消費者線程
					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();		
			  }
		   }
		}
	}
}
實際生產情況下使用阻塞隊列的情況居多!
發佈了15 篇原創文章 · 獲贊 3 · 訪問量 548
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章