Java基礎教程:多線程基礎(3)——阻塞隊列

Java基礎教程:多線程基礎(3)——阻塞隊列

快速開始

引入問題

  生產者消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一存儲空間,生產者向空間里生產數據,而消費者取走數據

模擬情景

  這里我們實現如下的情況的生產-消費模型:

生產者不斷交替地生產兩組數據“姓名--1-->內容--1”,“姓名--2-->內容--2”,這里的“姓名--1”和“姓名--2”模擬為數據的名稱,“內容--1 ”和“內容--2 ”模擬為數據的內容

由于本程序中牽扯到線程運行的不確定性,因此可能會出現以下問題:

  1.假設生產者線程剛向數據存儲空間添加了數據的名稱,還沒有加入該信息的內容,程序就切換到了消費者線程,消費者線程把信息的名稱和上一個信息的內容聯系到了一起;

  2.生產者生產了若干條數據,消費者才可以取數據,或者是,消費者取完一次數據后,還沒等生產者放入新的數據,又重復取出了已取過的數據。

通過分析我們可知:

  第一個問題可以通過同步來解決,第二個問題就需要用到線程通信。生產者線程放入數據后,通知消費者線程取出數據,消費者線程取出數據后,通知生產者線程生產數據,這里用wait\notigy機制來實現。

Java代碼

定義信息類

package thread;public class Info {private String name = "name";private String content = "content";//設置標志位,用來進行線程通信private boolean flag =true;/*** 設置消息,此處用到線程同步* @param name* @param content*/public synchronized void set(String name,String content){while (!flag){try {super.wait();} catch (InterruptedException e) {e.printStackTrace();}}this.name=name; //設置名稱try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}this.content=content; //設置內容flag =false; //設置標志位,表示現在生產停止,可以取走!}public synchronized void get(){while (flag){try {super.wait();} catch (InterruptedException e) {e.printStackTrace();}}try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(name +" --> " + content) ;flag  = true ;  // 改變標志位,表示可以生產super.notify();}}  

定義生產者

public class Producer implements Runnable {private Info info=null;public Producer(Info info){this.info=info;}@Overridepublic void run() {boolean flag = true ;   // 定義標記位for(int i=0;i<10;i++){if(flag){this.info.set("姓名--1","內容--1") ;    // 設置名稱flag = false ;}else{this.info.set("姓名--2","內容--2") ;    // 設置名稱flag = true ;}}}
}

定義消費者

public class Consumer implements Runnable {private Info info = null ;public Consumer(Info info){this.info = info ;}public void run(){for(int i=0;i<10;i++){this.info.get() ;}}public static void main(String[] args) {Info info = new Info(); // 實例化Info對象Producer pro = new Producer(info) ; // 生產者Consumer con = new Consumer(info) ; // 消費者new Thread(pro).start() ;//啟動了生產者線程后,再啟動消費者線程try{Thread.sleep(500) ;}catch(InterruptedException e){e.printStackTrace() ;}new Thread(con).start() ;}
}

?使用阻塞隊列來實現相同功能

引入BlockingQueue

  任何有效的生產者-消費者問題解決方案都是通過控制生產者put()方法(生產資源)和消費者take()方法(消費資源)的調用來實現的,一旦你實現了對方法的阻塞控制,那么你將解決該問題。Java通過BlockingQueue提供了開箱即用的支持來控制這些方法的調用(一個線程創建資源,另一個消費資源)。java.util.concurrent包下的BlockingQueue接口是一個線程安全的可用于存取對象的隊列

  

  BlockingQueue是一種數據結構支持一個線程往里存資源,另一個線程從里取資源。這正是解決生產者消費者問題所需要的,那么讓我們開始解決該問題吧。

Java代碼

消息類

public class InfoPlus {private String name = "name";private String content = "content";public InfoPlus(String name, String content) {this.name = name;this.content = content;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "InfoPlus{" +"name='" + name + '\'' +", content='" + content + '\'' +'}';}
}

生產者

import java.util.concurrent.BlockingQueue;public class ProducerPlus implements Runnable {private BlockingQueue<InfoPlus> queue;public ProducerPlus(BlockingQueue<InfoPlus> queue) {this.queue = queue;}@Overridepublic void run() {for (int i=0;i<10;i++){try {Thread.sleep(1000);queue.put(new InfoPlus("name"+i,"content"+i));} catch (InterruptedException e) {e.printStackTrace();}}}
}

消費者

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;public class ConsumerPlus implements Runnable{private BlockingQueue<InfoPlus> queue;public ConsumerPlus(BlockingQueue<InfoPlus> queue) {this.queue = queue;}public void run() {while (true) {try {System.out.println(this.queue.take());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {BlockingQueue<InfoPlus> blockingQueue = new LinkedBlockingDeque<>();ProducerPlus producerPlus = new ProducerPlus(blockingQueue);ConsumerPlus consumerPlus = new ConsumerPlus(blockingQueue);ConsumerPlus consumerPlus1 = new ConsumerPlus(blockingQueue);new Thread(producerPlus).start();new Thread(consumerPlus).start();new Thread(consumerPlus1).start();}
}

?

轉載于:https://www.cnblogs.com/MrSaver/p/9409838.html

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

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

相關文章

001.Linux開機啟動過程

相關Linux啟動過程解析&#xff0c;此作為通用啟動參考&#xff1a; 轉載于:https://www.cnblogs.com/itzgr/p/10285833.html

學習vim 從常用按鍵開始

撤銷 u 前進 ctrl r移動 下一個單詞 w 當前單詞首或上個單詞首 b 當前單詞尾或上個單詞尾 e ---- 大寫就是忽略標點符號 行首行尾 $^ 查詢 /word 下一個 n 上一個 Nv 可視化操作命令 刪除操作 x 刪除光標處的字符&#xff0c;向后刪除 nx …

element ui 中 el-menu 如何添加鏈接router-link標簽

在vue項目中&#xff0c;使用elementui 框架&#xff0c;做一個后臺管理系統 在寫左邊菜單&#xff0c;菜用了&#xff0c;elementui 提供的組件 &#xff0c; el-menu 組件。但是組件沒有鏈接&#xff0c;而我們知道添加鏈接使用router-link標簽代碼如下&#xff1a; <el-…

使用fastjson的parseObject方法將json字符串轉換成Map 或者List

fastjson 轉換成map HashMap<String,String> map JSON.parseObject(jsonStr,new TypeReference<HashMap<String,String>>() {}); fastjson 轉換成list List<Person> list new ArrayList<Person>(); list JSON.parseArray(jasonArray.toStri…

【01】《正則表達式必知必會》(已看)(僅存放)

【01】《正則表達式必知必會》 共149頁。掃描版&#xff0c;中文版。Sams Teach Yourselef Regular Expressions in 10 minutesBen Forta著。楊濤 翻譯【】魔芋&#xff1a;這本書已經沒有用了。內容已吸收。內容較為基礎&#xff0c;也很全面。** 附件列表 鏈接&#xff1a;ht…

vue-cli腳手架的.babelrc文件

{// 此項指明&#xff0c;轉碼的規則"presets": [// env項是借助插件babel-preset-env&#xff0c;下面這個配置說的是babel對es6,es7,es8進行轉碼&#xff0c;并且設置amd,commonjs這樣的模塊化文件&#xff0c;不進行轉碼["env", {"modules": …

Java秒殺業務架構設計之路

Java秒殺業務架構設計之路

疑難雜癥,逐個下藥

用戶登陸&#xff08;三次輸錯機會&#xff09;且每次輸錯誤時顯示剩余錯誤次數&#xff08;提示&#xff1a;使用字符串格式化&#xff09; 三次登錄: 1.讓用戶輸入三次的機會,錯一次的時候就要詢問用戶是否要繼續 2.分別判斷用戶名和密碼,如果用戶名錯誤就提示用戶錯誤,如果是…

JS性能分析(測試代碼運行時間)

console.time("timer"); for(var i0;i<10000;i){} console.timeEnd("timer"); timer: 0.274169921875ms轉載于:https://www.cnblogs.com/smzd/p/10647455.html

jsonp原生js跨域拿新浪數據插件封裝【可擴展】

//修改了一個bug,增加了手動釋放垃圾 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-…

Ansible基本命令

Ansible安裝完成之后就自帶很多命令&#xff0c;其中較常用的有7個&#xff1a; ansibleansible-docansible-galaxyansible-initansible-playbookansible-pullansible-vaultansible ansible -h Usage: ansible <host-pattern> [options] 對本機執行一個命令&#xff1a; …

Java高并發高性能分布式框架從無到有微服務架構設計

Java高并發高性能分布式框架從無到有微服務架構設計

Makefile中幾種賦值

延時變量&#xff0c;只有被使用時才展開定義 :?立即變量&#xff0c;定義時的賦值立即有效 ??條件變量&#xff0c;當變量為空時才賦值 追加賦值轉載于:https://www.cnblogs.com/smzd/p/10695962.html

線程的基本協作和生產者消費者

協作基礎&#xff08;wait/notify&#xff09; Java的根父類是Object&#xff0c;Java在Object類而非Thread類中&#xff0c;定義了一些線程協作的基本方法&#xff0c;使得每個對象都可以調用這些方法&#xff0c;這些方法有兩類&#xff0c;一類是wait&#xff0c;另一類是no…

L1-016 查驗身份證

L1-016 查驗身份證 &#xff08;15 分&#xff09;一個合法的身份證號碼由17位地區、日期編號和順序編號加1位校驗碼組成。校驗碼的計算規則如下&#xff1a; 首先對前17位數字加權求和&#xff0c;權重分配為&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff…

什么是高并發,如何避免高并發

之前我將高并發的解決方法誤認為是線程或者是隊列可以解決&#xff0c;因為高并發的時候是有很多用戶在訪問&#xff0c;導致出現系統數據不正確、丟失數據現象&#xff0c;所以想到 的是用隊列解決&#xff0c;其實隊列解決的方式也可以處理&#xff0c;比如我們在競拍商品、轉…

.sync 修飾符的理解

正常 子組件&#xff1a; this.$emit(update:title, newTitle)父組件&#xff1a; <text-documentv-bind:title"doc.title"v-on:update:title"doc.title $event" ></text-document>簡潔&#xff1a; <text-document v-bind:title.sync&quo…

L1-025 正整數A+B

題的目標很簡單&#xff0c;就是求兩個正整數A和B的和&#xff0c;其中A和B都在區間[1,1000]。稍微有點麻煩的是&#xff0c;輸入并不保證是兩個正整數。 輸入格式&#xff1a; 輸入在一行給出A和B&#xff0c;其間以空格分開。問題是A和B不一定是滿足要求的正整數&#xff0c;…

到底多大才算高并發?

一、什么是高并發 定義&#xff1a; 高并發(High Concurrency)是使用技術手段使系統可以并行處理很多請求。關鍵指標&#xff1a; -響應時間(Response Time) -吞吐量(Throughput) -每秒查詢率QPS(Query Per Second) -每秒事務處理量TPS(Transaction Per Second) -同時在…

eclipse安裝maven插件

1、在線安裝插件 a.打開eclipse&#xff0c;菜單“Help”-“Install New Software...” b.在Work with 地址欄輸入&#xff1a;http://download.eclipse.org/releases/對應eclipse版本名稱 c.在filter框中輸入maven d.選擇“Collaboration”-“m2e - Maven Integration for Ecl…