【Java并發】【LinkedBlockingQueue】適合初學體質的LinkedBlockingQueue入門

👋hi,我不是一名外包公司的員工,也不會偷吃茶水間的零食,我的夢想是能寫高端CRUD

🔥 2025本人正在沉淀中… 博客更新速度++

👍 歡迎點贊、收藏、關注,跟上我的更新節奏

📚歡迎訂閱專欄,專欄名《在2B工作中尋求并發是否搞錯了什么》

前言

你是否在線程池工具類里看到過它的身影?

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());

你是否會好奇LinkedBlockingQueue是啥呢?

沒有關系,小手手點上關注,跟上主播的節奏。

什么是LinkedBlockingQueue?

LinkedBlockingQueue 是一個基于鏈表的線程安全阻塞隊列,常用于生產者-消費者模式。

數據結構

  • 基于單向鏈表實現,隊列頭尾分別通過 head 和 last 指針維護。
  • 默認容量為 Integer.MAX_VALUE(近似無界隊列),但可手動指定固定容量。

線程安全

  • 使用兩把鎖分離設計(入隊鎖 putLock 和出隊鎖 takeLock),提高并發性能。
  • 通過 ReentrantLock 和 Condition 實現阻塞(隊列空時阻塞消費者,隊列滿時阻塞生產者)。

阻塞操作

  • put():隊列滿時阻塞生產者線程。
  • take():隊列空時阻塞消費者線程。
  • 非阻塞方法:offer()(失敗返回 false)、poll()(失敗返回 null)

簡單說說,和我們之前說的ArrayBlokcingQueue的區別:

特性LinkedBlockingQueueArrayBlockingQueue
底層結構鏈表數組
默認容量Integer.MAX_VALUE(無界)必須顯式指定
鎖機制雙鎖分離(更高并發)單鎖控制
內存占用動態擴展(鏈表節點開銷)預分配連續內存

簡單使用LinkedBlockingQueue

因為我們的LinkedBlockingQueue也是實現了BlockingQueue的接口,所以下面的代碼例子,會有這些方法。

在這里插入圖片描述

構造方法

首先從構造方法說起吧,LinkedBlockingQueue有3個構造方法:

// 沒有傳任何參數,默認容量大小為Integer.MAX_VALUE
public LinkedBlockingQueue();// 容量大小為入參
public LinkedBlockingQueue(int capacity)// 容量大小為Integer.MAX_VALUE,集合中初始化元素為c
public LinkedBlockingQueue(Collection<? extends E> c)

添加元素入隊操作

add(E e)方法:簡單粗暴,非阻塞添加元素,隊列滿了的話直接拋IllegalStateException異常。

public static void main(String[] args) {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);queue.add("A");queue.add("B"); // Exception in thread "main" java.lang.IllegalStateException: Queue full
}

offer(E e)方法:非阻塞添加元素,成功返回boolean,添加成功為true,添加失敗為false

public static void main(String[] args) {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);boolean result = queue.offer("A"); // trueSystem.out.println(result);result = queue.offer("B"); // falseSystem.out.println(result);
}

offer(E e, long timeout, TimeUnit unit)方法: 向隊列添加元素。如果隊列滿了,就阻塞線程,等待一段時間,一段時間過后隊列還是滿的話,意味添加元素失敗返回false,否則返回true。

public static void main(String[] args) throws InterruptedException {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);boolean result = queue.offer("A", 1, TimeUnit.SECONDS); // trueSystem.out.println(result);result = queue.offer("B", 1, TimeUnit.SECONDS); // falseSystem.out.println(result);
}

但如果我們這樣等待一會的話,執行結果就會不一樣:

public static void main(String[] args) throws InterruptedException {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);boolean result = queue.offer("A", 1, TimeUnit.SECONDS); // trueSystem.out.println(result);// 啟動另一個生產者線程new Thread(() -> {Boolean res;try {res = queue.offer("B", 2, TimeUnit.SECONDS); // 隊列滿了,阻塞2s等待} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(res);       // true}).start();// 移除隊列中的元素queue.poll();
}

put(E e)方法: 阻塞線程,直到隊列不為空或中斷者線程。

public static void main(String[] args) throws InterruptedException {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);queue.put("A");queue.put("B"); // 隊列已滿,線程阻塞在這
}

移除元素出隊操作

remove()方法:如果隊列為空,直接拋出NoSuchElementException異常。

public static void main(String[] args) {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);queue.remove(); // Exception in thread "main" java.util.NoSuchElementException
}

poll()方法:非阻塞獲取隊列頭元素,如果隊列為空,直接返回null。

public static void main(String[] args) {BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);String poll = queue.poll();System.out.println(poll); // null(隊列中沒有元素)queue.offer("A");      // 向隊列中添加元素poll= queue.poll();System.out.println(poll); // A
}

poll(long timeout, TimeUnit unit)方法:阻塞一段時間獲取隊列中的元素,如果超過時間了,就隊列還是為空,就返回null。

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);// 創建一個線程,3s后生產1個元素到隊列中new Thread(() -> {try {Thread.sleep(2000);queue.offer("A");} catch (InterruptedException e) {e.printStackTrace();}}).start();// 消費者,阻塞5s獲取元素String poll= queue.poll(5 , TimeUnit.SECONDS);System.out.println(poll); // A
}

take()方法:阻塞線程獲取隊列中的元素,直到隊列不為空,或者被其他線程中斷,拋出異常停止。

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);// 創建一個消費者線程,獲取隊列中的元素Thread consumerThread = new Thread(() -> {try {String take = queue.take();     // 在這個案例中,線程會被一直阻塞到這,直到被中斷System.out.println("消費者線程獲取到元素:" + take);} catch (InterruptedException e) {System.out.println("線程者線程被中斷了");}});consumerThread.start();// 隔3s后,中斷消費者線程TimeUnit.SECONDS.sleep(1);consumerThread.interrupt();
}輸出結果:
線程者線程被中斷了

檢查隊列中的元素

element() 方法: 返回隊列頭的元素,但是如果隊列為空,element方法會拋出NoSuchElementException異常。

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);queue.offer("A");queue.offer("B");System.out.println(queue.element());    // Aqueue.poll();   // 頭元素出隊System.out.println(queue.element());    // B
}// 異常的情況
public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);String element = queue.element();   // Exception in thread "main" java.util.NoSuchElementException
}

peek() 方法:和element()方法差不多,返回隊列頭的元素,如果隊列為空,會返回null

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);String element = queue.peek();System.out.println(element);    // null
}

后話

這就結束了?沒有的,寶貝,沒有的。

這里只是簡答的使用,小手手點上關注,主播下一篇,直接開始看LinkedBlockingQueue源碼。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80381.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80381.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80381.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python在AI虛擬教學視頻開發中的核心技術與前景展望

Python在AI虛擬教學視頻開發中的核心技術與前景展望 一、引言&#xff1a;AI虛擬教學的技術革新 隨著教育數字化轉型加速&#xff0c;AI虛擬教學視頻憑借個性化、沉浸式體驗成為教育科技的新風口。Python以其強大的多模態處理能力、豐富的開源生態和跨領域兼容性&#xff0c;成…

shadcn/radix-ui的tooltip高度定制arrow位置

嘗試了半天&#xff0c;后來發現&#xff0c;不支持。。。。。就是不支持 那箭頭只能居中 改side和align都沒用&#xff0c;下面有在線實例 https://codesandbox.io/p/sandbox/radix-ui-slider-forked-zgn7hj?file%2Fsrc%2FApp.tsx%3A69%2C21 但是呢&#xff0c; 第一如果…

自動清空 maven 項目臨時文件,vue 的 node_modules 文件

echo off setlocal enabledelayedexpansion :: vue 的 node_modules 太大 :: maven 打包后的 target 文件也很大&#xff0c; :: 有些項目日志文件也很大&#xff0c;導致磁盤空間不足了&#xff0c; :: 所以寫了個腳本&#xff0c;只要配置一下各項目目錄&#xff0c; :: 雙擊…

[Mybatis-plus]

簡介 MyBatis-Plus &#xff08;簡稱 MP&#xff09;是一個 MyBatis的增強工具&#xff0c;在 MyBatis 的基礎上只做增強不做改變。Mybatis-plus官網地址 注意&#xff0c;在引入了mybatis-plus之后&#xff0c;不要再額外引入mybatis和mybatis-spring&#xff0c;避免因為版本…

管理100個小程序-很難嗎

20公里的徒步-真難 群里的伙伴發起了一場天目山20公里徒步的活動&#xff0c;想著14公里都輕松拿捏了&#xff0c;思考了30秒后&#xff0c;就借著春風帶著老婆孩子就出發了。一開始溪流清澈見底&#xff0c;小橋流水沒有人家&#xff1b;青山郁郁蔥蔥&#xff0c;枯藤老樹沒有…

大模型工業化元年:GPT-5開啟通用AI新紀元,中國技術如何破局?

過去一周&#xff0c;AI領域的焦點無疑是OpenAI發布的GPT-5預覽版&#xff0c;以及全球大模型技術從實驗室邁向工業化的關鍵轉折。這場變革不僅標志著通用人工智能&#xff08;AGI&#xff09;的進一步逼近&#xff0c;更掀起了全球產業鏈的競爭與反思。本文將從技術突破、產業…

軟考【網絡工程師】2023年5月上午題答案解析

1、固態硬盤的存儲介質是()。 A 光盤 B 閃存 C 軟盤 D 磁盤 答案是 B。 固態硬盤(Solid State Drive),簡稱 SSD,是用固態電子存儲芯片陣列制成的硬盤,其存儲介質是閃存(Flash Memory)。閃存具有非易失性,即在斷電后仍能保留存儲的數據,且讀寫速度快、抗震性強、能…

【速寫】鉤子與計算圖

文章目錄 前向鉤子反向鉤子的輸入反向鉤子的輸出 前向鉤子 下面是一個測試用的計算圖的網絡&#xff0c;這里因為模型是自定義的緣故&#xff0c;可以直接把前向鉤子注冊在模型類里面&#xff0c;這樣會更加方便一些。其實像以前BERT之類的last_hidden_state以及pool_output之…

高級電影感戶外街拍人像攝影后期Lr調色教程,手機濾鏡PS+Lightroom預設下載!

調色介紹 高級電影感戶外街拍人像攝影后期 Lr 調色&#xff0c;是運用 Adobe Lightroom 軟件&#xff0c;對戶外街拍的人像照片進行后期處理&#xff0c;以塑造出具有電影質感的獨特視覺效果。此調色過程借助 Lr 豐富的工具與功能&#xff0c;從色彩、光影、對比度等多維度著手…

16.QT-Qt窗口-菜單欄|創建菜單欄|添加菜單|創建菜單項|添加分割線|添加快捷鍵|子菜單|圖標|內存泄漏(C++)

Qt窗?是通過QMainWindow類來實現的。 QMainWindow是?個為??提供主窗?程序的類&#xff0c;繼承?QWidget類&#xff0c;并且提供了?個預定義的布局。QMainWindow包含?個菜單欄&#xff08;menu bar&#xff09;、多個?具欄(tool bars)、多個浮動窗?&#xff08;鉚接部…

【kafka初學】啟動執行命令

接上篇&#xff0c;啟動&#xff1a;開兩個cdm窗口 注意放的文件不要太深或者中文&#xff0c;會報命令行太長的錯誤 啟動zookeeper bin\windows\zookeeper-server-start.bat config\zookeeper.properties2. 啟動kafka-serve bin\windows\kafka-server-start.bat config\serv…

利用 Claw Cloud Run 免費應用部署前端網頁

一、注冊 使用注冊180天的github賬戶注冊Claw Cloud賬戶&#xff0c;可獲得每月5$的免費配額官網鏈接 - https://run.claw.cloud/ &#xff08;ps&#xff1a;直接github賬號登錄應該就不用寫了吧&#xff09; 二、創建應用 打開App Launchpad 點擊Create AppCPU選0.1即可&a…

豆瓣圖書數據采集與可視化分析(三)- 豆瓣圖書數據統計分析

文章目錄 前言一、數據讀取與保存1. 讀取清洗后數據2. 保存數據到CSV文件3. 保存數據到MySQL數據庫 二、不同分類統計分析1. 不同分類的圖書數量統計分析2. 不同分類的平均評分統計分析3. 不同分類的平均評價人數統計分析4. 不同分類的平均價格統計分析5. 分類綜合分析 三、不同…

網絡原理 - 3(UDP 協議)

目錄 協議 應用層 xml json protobuffer 傳輸層 端口號&#xff08;Port&#xff09; UDP 協議 UDP 協議端格式 完&#xff01; 協議 網絡通信中&#xff0c;協議是一個非常重要的概念。我們前面在網絡原理中&#xff0c;就已經介紹了&#xff0c;為了統一各方網絡&…

Java Agent 注入 WebSocket 篇

Agent 如果要對其進行Agent注入的編寫&#xff0c;需要先理解三個名字premain&#xff0c;agentmain&#xff0c;Instrumentation premain方法在 JVM 啟動階段調用&#xff0c;一般維持權限的時候不會使用 agentmain方法在 JVM 運行時調用 常用的 Instrumentation實例為代理…

【深度強化學習 DRL 快速實踐】近端策略優化 (PPO)

PPO&#xff08;2017&#xff0c;OpenAI&#xff09;核心改進點 Proximal Policy Optimization (PPO)&#xff1a;一種基于信賴域優化的強化學習算法&#xff0c;旨在克服傳統策略梯度方法在更新時不穩定的問題&#xff0c;采用簡單易實現的目標函數來保證學習過程的穩定性 解決…

筆試強訓:Day2

一、字符串中找出連續最長的數字串(雙指針) 字符串中找出連續最長的數字串_牛客題霸_牛客網 #include <iostream> #include <string> #include <cctype> using namespace std;int main() {//雙指針string str;cin>>str;int nstr.size();int begin-1,l…

MySQL 詳解之 InnoDB:核心特性深度剖析 (ACID, 事務, 鎖, 外鍵, 崩潰恢復)

在 MySQL 的世界里,存儲引擎是數據庫管理系統的核心組成部分,它負責數據的存儲和提取。MySQL 支持多種存儲引擎,如 MyISAM, Memory, CSV 等,但自 MySQL 5.5 版本以來,InnoDB 成為了默認的存儲引擎,也是絕大多數應用場景的首選。 為什么 InnoDB 如此重要并被廣泛采用?因…

Java中正則表達式使用方法

1. 正則表達式概述 正則表達式&#xff08;Regular Expression&#xff0c;簡稱 Regex&#xff09;是一種用于匹配字符串的模式工具。在 Java 中&#xff0c;正則表達式通過 java.util.regex 包實現&#xff0c;主要涉及以下兩個類&#xff1a; Pattern&#xff1a;表示一個編…

使用瀏覽器的Clipboard API實現前端復制copy功能

在前端開發中&#xff0c;復制文本到剪貼板的功能通常使用瀏覽器的 Clipboard API 實現。比如 navigator.clipboard.writeText 方法。以下是一個簡單的案例&#xff0c;展示如何使用 Clipboard API 實現復制文本的功能。 基本用法 首先&#xff0c;你需要創建一個按鈕&#x…