一: Queue詳解
Queue: 基本上,一個隊列就是一個先入先出(FIFO)的數據結構
Queue接口與List、Set同一級別,都是繼承了Collection接口。LinkedList實現了Deque接 口。
1)、沒有實現的阻塞接口的LinkedList: 實現了java.util.Queue接口和java.util.AbstractQueue接口
內置的不阻塞隊列: PriorityQueue 和 ConcurrentLinkedQueue
PriorityQueue 和 ConcurrentLinkedQueue 類在 Collection Framework 中加入兩個具體集合實現。
PriorityQueue 類實質上維護了一個有序列表。加入到 Queue 中的元素根據它們的天然排序(通過其 java.util.Comparable 實現)或者根據傳遞給構造函數的 java.util.Comparator 實現來定位。
ConcurrentLinkedQueue 是基於鏈接節點的、線程安全的隊列。並發訪問不需要同步。因為它在隊列的尾部添加元素並從頭部刪除它們,所以只要不需要知道隊列的大 小,ConcurrentLinkedQueue 對公共集合的共享訪問就可以工作得很好。收集關於隊列大小的信息會很慢,需要遍歷隊列。
2)、實現阻塞接口的:
java.util.concurrent 中加入了 BlockingQueue 接口和五個阻塞隊列類。它實質上就是一種帶有一點扭曲的 FIFO 數據結構。不是立即從隊列中添加或者刪除元素,線程執行操作阻塞,直到有空間或者元素可用。
五個隊列所提供的各有不同:
* ArrayBlockingQueue :一個由數組支持的有界隊列。
* LinkedBlockingQueue :一個由鏈接節點支持的可選有界隊列。
* PriorityBlockingQueue :一個由優先級堆支持的無界優先級隊列。
* DelayQueue :一個由優先級堆支持的、基於時間的調度隊列。
* SynchronousQueue :一個利用 BlockingQueue 接口的簡單聚集(rendezvous)機制。
下表顯示了jdk1.5中的阻塞隊列的操作:
add 增加一個元索 如果隊列已滿,則拋出一個IIIegaISlabEepeplian異常
remove 移除並返回隊列頭部的元素 如果隊列為空,則拋出一個NoSuchElementException異常
element 返回隊列頭部的元素 如果隊列為空,則拋出一個NoSuchElementException異常
offer 添加一個元素並返回true 如果隊列已滿,則返回false
poll 移除並返問隊列頭部的元素 如果隊列為空,則返回null
peek 返回隊列頭部的元素 如果隊列為空,則返回null
put 添加一個元素 如果隊列滿,則阻塞
take 移除並返回隊列頭部的元素 如果隊列為空,則阻塞
3)、示例
1 package com.svse.queue; 3 import java.util.LinkedList; 4 import java.util.Queue; 7 import java.util.Timer; 8 import java.util.TimerTask; 10 import com.svse.entity.Users; 11 12 class TestQueue { 13 14 static Queue<Users> queueUsers=new LinkedList<Users>(); 15 static{ 16 Users user1=new Users("201","張三","男","27","歌手"); 17 Users user2=new Users("202","李思","女","26","演員"); 18 queueUsers.add(user1); 19 queueUsers.add(user2); 20 } 21 22 public void test1(){ 23 24 Queue<String> queue = new LinkedList<String>(); 25 queue.offer("Hello"); 26 queue.offer("World!"); 27 queue.offer("你好!"); 28 29 System.out.println(queue.size()); 30 31 32 while (queue.size() > 0) { 33 String element = queue.poll(); 34 System.out.println(element); 35 } 36 System.out.println(); 37 System.out.println(queue.size()); 38 } 39 40 //生產者 41 public void producerQueue(){ 42 43 System.out.println(queueUsers.size()); 44 } 45 46 //消費者 47 public void consumerQueue(){ 48 Users u=null; 49 while((u=queueUsers.poll())!=null){ 50 System.out.println(u+" "); 51 } 52 System.out.println(); 53 System.out.println(queueUsers.size()); 54 } 55 69 70 public static void main(String[] args) { 71 TestQueue tq=new TestQueue(); 72 //tq.producerQueue(); 73 //tq.consumerQueue(); 74 75 timerTest(); 76 77 78 79 } 80 81 }
二: 不怕難之BlockingQueue及其實現
1)、 前言
BlockingQueue即阻塞隊列,它是基於ReentrantLock,依據它的基本原理,我們可以實現Web中的長連接聊天功能,當然其最常用的還是用於實現生產者與消費者模式,大致如下圖所示:
2)、阻塞與非阻塞
入隊
offer(E e):如果隊列沒滿,立即返回true; 如果隊列滿了,立即返回false-->不阻塞
put(E e):如果隊列滿了,一直阻塞,直到隊列不滿了或者線程被中斷-->阻塞
offer(E e, long timeout, TimeUnit unit):在隊尾插入一個元素,,如果隊列已滿,則進入等待,直到出現以下三種情況:-->阻塞
被喚醒
等待時間超時
當前線程被中斷
出隊
poll():如果沒有元素,直接返回null;如果有元素,出隊
take():如果隊列空了,一直阻塞,直到隊列不為空或者線程被中斷-->阻塞
poll(long timeout, TimeUnit unit):如果隊列不空,出隊;如果隊列已空且已經超時,返回null;如果隊列已空且時間未超時,則進入等待,直到出現以下三種情況:
被喚醒
等待時間超時
當前線程被中斷
3)、示例
1 package com.yao; 2 import java.util.concurrent.ArrayBlockingQueue; 3 import java.util.concurrent.BlockingQueue; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.Executors; 6 public class BlockingQueueTest { 7 /** 8 定義裝蘋果的籃子 9 */ 10 public static class Basket{ 11 // 籃子,能夠容納3個蘋果 12 BlockingQueue<String> basket = new ArrayBlockingQueue<String>(3); 13 14 // 生產蘋果,放入籃子 15 public void produce() throws InterruptedException{ 16 // put方法放入一個蘋果,若basket滿了,等到basket有位置 17 basket.put("An apple"); 18 } 19 // 消費蘋果,從籃子中取走 20 public String consume() throws InterruptedException{ 21 // get方法取出一個蘋果,若basket為空,等到basket有蘋果為止 22 String apple = basket.take(); 23 return apple; 24 } 25 26 public int getAppleNumber(){ 27 return basket.size(); 28 } 29 30 } 31 // 測試方法 32 public static void testBasket() { 33 // 建立一個裝蘋果的籃子 34 final Basket basket = new Basket(); 35 // 定義蘋果生產者 36 class Producer implements Runnable { 37 public void run() { 38 try { 39 while (true) { 40 // 生產蘋果 41 System.out.println("生產者准備生產蘋果:" 42 + System.currentTimeMillis()); 43 basket.produce(); 44 System.out.println("生產者生產蘋果完畢:" 45 + System.currentTimeMillis()); 46 System.out.println("生產完后有蘋果:"+basket.getAppleNumber()+"個"); 47 // 休眠300ms 48 Thread.sleep(300); 49 } 50 } catch (InterruptedException ex) { 51 } 52 } 53 } 54 // 定義蘋果消費者 55 class Consumer implements Runnable { 56 public void run() { 57 try { 58 while (true) { 59 // 消費蘋果 60 System.out.println("消費者准備消費蘋果:" 61 + System.currentTimeMillis()); 62 basket.consume(); 63 System.out.println("消費者消費蘋果完畢:" 64 + System.currentTimeMillis()); 65 System.out.println("消費完后有蘋果:"+basket.getAppleNumber()+"個"); 66 // 休眠1000ms 67 Thread.sleep(1000); 68 } 69 } catch (InterruptedException ex) { 70 } 71 } 72 } 73 74 ExecutorService service = Executors.newCachedThreadPool(); 75 Producer producer = new Producer(); 76 Consumer consumer = new Consumer(); 77 service.submit(producer); 78 service.submit(consumer); 79 // 程序運行10s后,所有任務停止 80 try { 81 Thread.sleep(10000); 82 } catch (InterruptedException e) { 83 } 84 service.shutdownNow(); 85 }
86 87 public static void main(String[] args) { 88 BlockingQueueTest.testBasket(); 89 } 90 }
三: 定時器之Timer
1 package com.svse.queue; 2 import java.util.Timer; 3 import java.util.TimerTask; 4 5 public class TestTimer { 6 7 8 static int i=0; 9 public static void timerTest(){ 10 //創建一個定時器 11 Timer timer = new Timer(); 12 //schedule方法是執行時間定時任務的方法 13 timer.schedule(new TimerTask() { 14 @Override 15 public void run() { 16 i++; 17 System.out.println("timerTest: "+i); 18 } 19 }, 1000, 60000); //第一個參數時間 從多少毫秒之后開始執行 第二個時間參數 間隔多少毫秒之后再執行 1分鍾一次 20 } 21 22 23 public static void main(String[] args) { 24 25 timerTest(); 26 27 } 28 29 }