J.U.C系列(五)BlockingQueue的使用
BlockingQueue
java.util.concurrent.BlockingQueue 接口有以下阻塞隊列的實現:
- FIFO 隊列 :LinkedBlockingQueue、ArrayBlockingQueue(固定長度)
優(yōu)先級隊列 :PriorityBlockingQueue - 提供了阻塞的 take() 和 put() 方法:如果隊列為空 take() 將阻塞,直到隊列中有內容;如果隊列為滿 put() 將阻塞,直到隊列有空閑位置。
其實,這個BlockingQueue是一個接口,Java中給我們提供了以下幾個實現類。
ArrayBlockingQueue:ArrayBlockingQueue 是一個有界的阻塞隊列,其內部實現是將對象放到一個數組里。有界也就意味著,它不能夠存儲無限多數量的元素。它有一個同一時間能夠存儲元素數量的上限。你可以在對其初始化的時候設定這個上限,但之后就無法對這個上限進行修改了(譯者注:因為它是基于數組實現的,也就具有數組的特性:一旦初始化,大小就無法修改)。
DelayQueue:DelayQueue 對元素進行持有直到一個特定的延遲到期。注入其中的元素必須實現 java.util.concurrent.Delayed 接口。
LinkedBlockingQueue:LinkedBlockingQueue 內部以一個鏈式結構(鏈接節(jié)點)對其元素進行存儲。如果需要的話,這一鏈式結構可以選擇一個上限。如果沒有定義上限,將使用 Integer.MAX_VALUE 作為上限。
PriorityBlockingQueue:PriorityBlockingQueue 是一個無界的并發(fā)隊列。它使用了和類 java.util.PriorityQueue 一樣的排序規(guī)則。你無法向這個隊列中插入 null 值。所有插入到 PriorityBlockingQueue 的元素必須實現 java.lang.Comparable 接口。因此該隊列中元素的排序就取決于你自己的 Comparable 實現。
SynchronousQueue:SynchronousQueue 是一個特殊的隊列,它的內部同時只能夠容納單個元素。如果該隊列已有一元素的話,試圖向隊列中插入一個新元素的線程將會阻塞,直到另一個線程將該元素從隊列中抽走。同樣,如果該隊列為空,試圖向隊列中抽取一個元素的線程將會阻塞,直到另一個線程向隊列中插入了一條新的元素。據此,把這個類稱作一個隊列顯然是夸大其詞了。它更多像是一個匯合點。
阻塞隊列最常見的使用例子就是生產者消費者模式,使用 BlockingQueue 實現生產者消費者問題
package com.leo.demo.juctest;import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue;/*** @ClassName: ProducerConsumerExample* @Description: 生產者消費者* @Author: leo825* @Date: 2020-05-14 00:09* @Version: 1.0*/ public class ProducerConsumerExample {//生產產品列表private static BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);//獲取一個隨機數//生產者private static class Producer extends Thread {//線程名String name;Producer(String name) {this.name = name;}@Overridepublic void run() {try {int costTime = new Random().nextInt(1000);Thread.sleep(costTime);getThreadLog("【生產蛋糕_" + this.name + "】耗時:" + costTime + "ms");queue.put(this.name);} catch (InterruptedException e) {e.printStackTrace();}}}//消費者private static class Consumer extends Thread {//線程名String name;Consumer(String name) {this.name = name;}@Overridepublic void run() {String cake = null;try {cake = queue.take();int costTime = new Random().nextInt(1000);Thread.sleep(costTime);getThreadLog("【消費蛋糕_"+ cake + "】耗時:" + costTime + "ms");} catch (InterruptedException e) {e.printStackTrace();}}}public static void getThreadLog(String logContent) {StringBuffer stringBuffer = new StringBuffer();stringBuffer.append("[");stringBuffer.append(Thread.currentThread().getName());stringBuffer.append(" ");stringBuffer.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));stringBuffer.append("]");stringBuffer.append(logContent);System.out.println(stringBuffer.toString());}public static void main(String[] args) {//定義5個生產蛋糕的int producerNum = 5;//定義5個吃蛋糕的int consumerNum = 5;//生產者開始生產蛋糕for (int i = 0; i < producerNum; i++) {Producer producer = new Producer("produce_cake_" + i);producer.start();}//消費者消費蛋糕for (int j = 0; j < consumerNum; j++) {Consumer consumer = new Consumer("consume_cake_" + j);consumer.start();}} }打印結果:
[Thread-3 2020-05-14 11:17:06.720]【生產蛋糕_produce_cake_3】耗時:258ms [Thread-0 2020-05-14 11:17:06.952]【生產蛋糕_produce_cake_0】耗時:569ms [Thread-2 2020-05-14 11:17:07.002]【生產蛋糕_produce_cake_2】耗時:617ms [Thread-7 2020-05-14 11:17:07.059]【消費蛋糕_produce_cake_2】耗時:56ms [Thread-1 2020-05-14 11:17:07.134]【生產蛋糕_produce_cake_1】耗時:753ms [Thread-4 2020-05-14 11:17:07.206]【生產蛋糕_produce_cake_4】耗時:823ms [Thread-5 2020-05-14 11:17:07.710]【消費蛋糕_produce_cake_3】耗時:980ms [Thread-8 2020-05-14 11:17:07.834]【消費蛋糕_produce_cake_1】耗時:693ms [Thread-6 2020-05-14 11:17:07.873]【消費蛋糕_produce_cake_0】耗時:921ms [Thread-9 2020-05-14 11:17:08.144]【消費蛋糕_produce_cake_4】耗時:912ms總結
以上是生活随笔為你收集整理的J.U.C系列(五)BlockingQueue的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java多线程中volatile关键字
- 下一篇: J.U.C系列(六)ForkJoin的使