import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class TestBlockingQueue { public static void main(String[] args) { final BlockingQueue<Integer> queue=new LinkedBlockingQueue<Integer>(3); final Random random=new Random(); class PRoducer implements Runnable{ @Override public void run() { while(true){ try { int i=random.nextInt(100); queue.put(i);//當隊列達到容量時候,會自動阻塞的 if(queue.size()==3) { System.out.println("full"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ @Override public void run() { while(true){ try { queue.take();//當隊列為空時,也會自動阻塞 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } new Thread(new Producer()).start(); new Thread(new Consumer()).start(); } } 總結:BlockingQueue使用時候特別注意take 和 put 8. DelayQueue 我們先來學習一下JDK1.5 API中關于這個類的詳細介紹: “它是包含Delayed 元素的一個無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部 是延遲期滿后保存時間最長的 Delayed 元素。如果延遲都還沒有期滿,則隊列沒有頭部,并且 poll 將返回 null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小于等于 0 的值時,將發生到期。即使無法使用 take 或 poll 移除未到期的元素,也不會將這些元素作為正常元素對待。例如,size 方法同時返回到期和未到期元素的計數。此隊列不允許使用 null 元素。” 在現實生活中,很多DelayQueue的例子。就拿上海的SB會來說明,很多國家地區的開館時間不同。你很早就來到園區,然后急急忙忙地跑到一些心儀的館區,發現有些還沒開,你吃了閉門羹。 仔細研究DelayQueue,你會發現它其實就是一個PriorityQueue的封裝(按照delay時間排序),里面的元素都實現了Delayed接口,相關操作需要判斷延時時間是否到了。 在實際應用中,有人拿它來管理跟實際相關的緩存、session等 下面我就通過 “上海SB會的例子來闡述DelayQueue的用法” 代碼如下: import java.util.Random; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class TestDelayQueue { private class Stadium implements Delayed { long trigger; public Stadium(long i){ trigger=System.currentTimeMillis()+i; } @Override public long getDelay(TimeUnit arg0) { long n=trigger-System.currentTimeMillis(); return n; } @Override public int compareTo(Delayed arg0) { return (int)(this.getDelay(TimeUnit.MILLISECONDS)-arg0.getDelay(TimeUnit.MILLISECONDS)); } public long getTriggerTime(){ return trigger; } } public static void main(String[] args)throws Exception { Random random=new Random(); DelayQueue<Stadium> queue=new DelayQueue<Stadium>(); TestDelayQueue t=new TestDelayQueue(); for(int i=0;i<5;i++){ queue.add(t.new Stadium(random.nextInt(30000))); } Thread.sleep(2000); while(true){ Stadium s=queue.take();//延時時間未到就一直等待 if(s!=null){ System.out.println(System.currentTimeMillis()-s.getTriggerTime());//基本上是等于0 } if(queue.size()==0) break; } } } 總結:適用于需要延時操作的隊列管理9. SynchronousQueue 我們先來學習一下JDK1.5 API中關于這個類的詳細介紹: “一種阻塞隊列,其中每個插入操作必須等待另一個線程的對應移除操作 ,反之亦然。同步隊列沒有任何內部容量,甚至連一個隊列的容量都沒有。不能在同步隊列上進行 peek,因為僅在試圖要移除元素時,該元素才存在;除非另一個線程試圖移除某個元素,否則也不能(使用任何方法)插入元素;也不能迭代隊列,因為其中沒有元素可用于迭代。隊列的頭 是嘗試添加到隊列中的首個已排隊插入線程的元素;如果沒有這樣的已排隊線程,則沒有可用于移除的元素并且 poll() 將會返回 null。對于其他 Collection 方法(例如 contains),SynchronousQueue 作為一個空 collection。此隊列不允許 null 元素。 同步隊列類似于 CSP 和 Ada 中使用的 rendezvous 信道。它非常適合于傳遞性設計,在這種設計中,在一個線程中運行的對象要將某些信息、事件或任務傳遞給在另一個線程中運行的對象,它就必須與該對象同步。 “ 看起來很有意思吧。隊列竟然是沒有內部容量的。這個隊列其實是BlockingQueue的一種實現。每個插入操作必須等待另一個線程的對應移除操作,反之亦然。它給我們提供了在線程之間交換單一元素的極輕量級方法 應用舉例:我們要在多個線程中傳遞一個變量。 代碼如下(其實就是生產者消費者模式) import java.util.Arrays; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.SynchronousQueue; public class TestSynchronousQueue { class Producer implements Runnable { private BlockingQueue<String> queue; List<String> objects = Arrays.asList("one", "two", "three"); public Producer(BlockingQueue<String> q) { this.queue = q; } @Override public void run() { try { for (String s : objects) { queue.put(s);// 產生數據放入隊列中 System.out.printf("put:%s%n",s); } queue.put("Done");// 已完成的標志 } catch (InterruptedException e) { e.printStackTrace(); } } } class Consumer implements Runnable { private BlockingQueue<String> queue; public Consumer(BlockingQueue<String> q) { this.queue = q; } @Override public void run() { String obj = null; try { while (!((obj = queue.take()).equals("Done"))) { System.out.println(obj);//從隊列中讀取對象 Thread.sleep(3000); //故意sleep,證明Producer是put不進去的 } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { BlockingQueue<String> q=new SynchronousQueue<String>(); TestSynchronousQueue t=new TestSynchronousQueue(); new Thread(t.new Producer(q)).start(); new Thread(t.new Consumer(q)).start(); } } 總結:SynchronousQueue主要用于單個元素在多線程之間的傳遞
新聞熱點
疑難解答