進階篇:同步阻塞佇列之LinkedBlockingQueue(十一)
阿新 • • 發佈:2019-02-05
JDK為我們提供了多個阻塞佇列的實現,什麼是阻塞佇列呢? 我們都知道佇列就是一組資料的集合,而阻塞佇列的意思是,當你往佇列中取資料時,如果沒有資料,你將被阻塞,一直等到拿到資料為止;
今天我們就來看一下比較常用的遵循先進先出的阻塞佇列LinkedBlockingQueue;
//同步阻塞佇列 //可以看到,當呼叫take()方法去拿資料時,如果裡面沒有資料,將造成阻塞 public static void blockingQueue(){ final BlockingQueue<String> queue = new LinkedBlockingQueue<>(); ExecutorService exec = Executors.newCachedThreadPool(); //一個執行緒不斷的往佇列中取東西 exec.execute(new Runnable() { public void run() { while( !Thread.currentThread().isInterrupted() ){ try { String value = queue.take(); System.out.println("執行緒"+Thread.currentThread()+"拿到資料:"+value); } catch (InterruptedException e) { e.printStackTrace(); } } } }); //一個執行緒不斷的往佇列中放東西 exec.execute(new Runnable() { public void run() { while( !Thread.currentThread().isInterrupted() ){ try { TimeUnit.MILLISECONDS.sleep(1000); int number = new Random().nextInt(1000); System.out.println("寫入資料:"+number); queue.put(number+""); } catch (InterruptedException e) { e.printStackTrace(); } } } }); }
簡單吧!一個執行緒寫資料,一個執行緒讀資料,當讀資料的執行緒呼叫queue.take()往佇列中拿資料時,如果佇列中沒有資料,它就一直阻塞,直到寫資料的執行緒通過queue.put()方法寫入資料為止! 是不是比我們自己寫wait()和notify()要簡單好用的多呢?!
對比上一篇文章的生產者消費者的實現,如果我們採用阻塞佇列來實現的話,會變成什麼樣子呢?我們來看一下吧!
//餐廳 class BlockingRestaurant{ public BlockingQueue<String> queue = new LinkedBlockingQueue<>(); } //食物消費者(顧客) class BlockingConsumer{ //在這家餐廳就餐 private BlockingRestaurant res = null; public BlockingConsumer( BlockingRestaurant res ) { this.res = res; } //吃食物方法 public void eat() throws InterruptedException{ while( !Thread.currentThread().isInterrupted() ){ if( res.queue.take()!=null ){ System.out.println("開始吃食物..."); TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));//吃食物時間 System.out.println("食物吃完了!..."); } } } } //食物提供者(廚師) class BlockingProvider{ //在這家餐廳工作 private BlockingRestaurant res = null; public BlockingProvider( BlockingRestaurant res ) { this.res = res; } public void fry() throws InterruptedException{//炒菜 while( !Thread.currentThread().isInterrupted() ){ System.out.println("開始做食物..."); TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000)); res.queue.put("一份食物"); System.out.println("食物做完了!..."); } } }
//經典生產者與消費者演示(採用佇列) public static void producerByQueue(){ ExecutorService exec = Executors.newCachedThreadPool(); BlockingRestaurant res = new BlockingRestaurant(); final BlockingConsumer consumer = new BlockingConsumer(res); final BlockingProvider provider = new BlockingProvider(res); exec.execute(new Runnable() { public void run() { try { consumer.eat(); } catch (InterruptedException e) { e.printStackTrace(); } } }); exec.execute(new Runnable() { public void run() { try { provider.fry(); } catch (InterruptedException e) { e.printStackTrace(); } } }); }
簡單多了吧! Ok,這就是LinkedBlockingQueue的使用方法,後面我們會再介紹優先順序佇列,延時佇列等等多種佇列,它們將實現更有趣的功能!