用Java解決生產者-消費者問題

當我們嘗試多線程編程時,生產者-消費者問題是最常見的問題之一。 盡管不像多線程編程中的其他一些問題那樣具有挑戰性,但是錯誤地實現此問題可能會造成應用程序混亂。 生產的物品將不使用,開始的物品將被跳過,消耗量取決于生產是在消耗嘗試之前還是之后開始的,等等。此外,您可能會在異常發生后很長時間注意到異常,最重要的是,幾乎所有異常線程程序,這一程序也很難調試和復制。
因此,在這篇文章中,我認為我將嘗試借助Java出色的java.util.concurrent包及其類來解決Java中的此問題。
首先,讓我們看一下生產者-消費者問題的特征:
  • 生產者生產物品。
  • 消費者消費生產者生產的物品。
  • 生產者完成生產,并讓消費者知道他們已經完成了。
請注意,在此生產者-消費者問題中,生產者運行在與消費者不同的線程上。 此設置在兩種情況下有意義:
  • 消耗該項目的步驟獨立產生,而不依賴于其他項目。
  • 處理項目的時間大于生產項目的時間。
第二點中的“較大”一詞有些寬松。 考慮以下情況:生產者從文件中讀取一行,而“消耗和處理”只是將行以特殊格式記錄回文件中,那么使用生產者消費者問題解決方案可以被認為是過度設計的情況一個解法。 但是,如果對于每行,“消耗和處理”步驟是向Web服務器發出HTTP GET / POST請求,然后將結果轉儲到某個地方,則我們應該選擇生產者-消費者解決方案。 在這種情況下,我假設行(item)本身具有執行GET / POST的所有數據,而我們不依賴于上一行/下一行。
因此,讓我們首先看一下我在下面發布的生產者-消費者問題解決方案的特征:
  • 可以有多個生產者。
  • 將有多個消費者。
  • 一旦完成新物品的生產,生產者將告知消費者,以便消費者在消費并加工完最后一件物品后退出。
有趣的是,要在通用級別解決此問題,我們只能解決消費者方,而不能解決生產方。 這是因為項目的生產可以隨時進行,而我們以通用方式進行項目生產的控制幾乎沒有。 但是,我們可以在接受生產者提供的商品時控制消費者的行為。 制定了規則之后,讓我們看一下消費者合同:
package com.maximus.producerconsumer;public interface Consumer
{public boolean consume(Item j);public void finishConsumption();
}

在這里,可以由多個類似商品的生產者共享消費者。 類似的項目,我的意思是生產者,其生產“項目”類型的對象。 Item的定義如下:

package com.maximus.consumer;public interface Item
{public void process();
}

現在我們來看一下Consumer接口的實現:

package com.maximus.consumer;import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;public class ConsumerImpl implements Consumer
{private BlockingQueue< Item > itemQueue = new LinkedBlockingQueue<Item>();private ExecutorService executorService = Executors.newCachedThreadPool();private List<ItemProcessor> jobList = new LinkedList<ItemProcessor>();private volatile boolean shutdownCalled = false;public ConsumerImpl(int poolSize){for(int i = 0; i < poolSize; i++){ItemProcessor jobThread = new ItemProcessor(itemQueue);jobList.add(jobThread);executorService.submit(jobThread);}}public boolean consume(Item j){if(!shutdownCalled){try{itemQueue.put(j);}catch(InterruptedException ie){Thread.currentThread().interrupt();return false;}return true;}else{return false;}}public void finishConsumption(){for(ItemProcessor j : jobList){j.cancelExecution();}executorService.shutdown();}
}

現在,唯一感興趣的點是消費者內部用于處理傳入商品的ItemProcessor。 ItemProcessor的編碼如下:

package com.maximus.consumer;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;public class ItemProcessor implements Runnable
{private BlockingQueue<Item> jobQueue;private volatile boolean keepProcessing;public ItemProcessor(BlockingQueue<Item> queue){jobQueue = queue;keepProcessing = true;}public void run(){while(keepProcessing || !jobQueue.isEmpty()){try{Item j = jobQueue.poll(10, TimeUnit.SECONDS);if(j != null){j.process();}}catch(InterruptedException ie){Thread.currentThread().interrupt();return;}}}public void cancelExecution(){this.keepProcessing = false;}
}
上面唯一的挑戰是while循環中的條件。 這樣編寫while循環,即使在生產者完成生產并通知消費者生產完成之后,也可以支持項目消耗的繼續。 上面的while循環可確保在線程退出之前完成所有項目的消耗。
上面的使用者是線程安全的,可以共享多個生產者,以便每個生產者可以并發調用consumer.consume(),而不必擔心同步和其他多線程警告。 生產者只需要提交Item接口的實現,其process()方法將包含如何完成消耗的邏輯。
作為閱讀本文的獎勵,我提出了一個測試程序,演示了如何使用上述類:
package com.maximus.consumer;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;public class Test
{public static void main(String[] args) throws Exception{Consumer consumer = new ConsumerImpl(10);BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(args[0]))));String line = "";while((line = br.readLine()) != null){System.out.println("Producer producing: " + line);consumer.consume(new PrintJob(line));}consumer.finishConsumption();}
}class PrintJob implements Item
{private String line;public PrintJob(String s){line = s;}public void process(){System.out.println(Thread.currentThread().getName() + " consuming :" + line);}
}
可以通過多種不同的方式來調整上述消費者,使其更加靈活。 我們可以定義生產完成后消費者將做什么。 可能對其進行了調整,以允許批處理,但我將其留給用戶使用。 隨意使用它,并以任何想要的方式扭曲它。
編碼愉快!

參考: The Java HotSpot博客上的JCG合作伙伴 Sarma Swaranga 解決了Java中的生產者-消費者問題 。


翻譯自: https://www.javacodegeeks.com/2012/05/solving-producer-consumer-problem-in.html

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

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

相關文章

哪位科學家奠定了計算機結構理論,計算機等級考試一級理論知識選擇題題庫(1-50)...

領域中的問題為主的數值計算稱為科學計算B)計算機應用可分為數值應用和非數值應用兩類C)計算機各部件之間有兩股信息流&#xff0c;即數據流和控制流D)對信息(即各種形式的數據)進行收集、儲存、加工與傳輸等一系列活動的總稱為實時控制答案&#xff1a;D32. 金卡工程是我國正在…

axios 參數為payload的解決方法

1. 添加頭部headers headers: {Content-Type: application/x-www-form-urlencoded,}, axios.post(url, {a: 1, b:2}, {headers: {Content-Type: application/x-www-form-urlencoded,}, }).then(response > response.data).then(err > {console.log(err);}); 2. 在Browser…

超出了GC開銷限制– Java堆分析

這篇文章是我們原來的GC超出限制的問題模式帖子的延續。 正確的Java堆分析對于消除O??utOfMemoryError&#xff1a;GC開銷問題至關重要。 如果您不熟悉此Java HotSpot 1.6錯誤&#xff0c;建議您首先閱讀有關此主題的第一篇文章 。 本文將為您提供一個示例程序和一個教程&…

開燈問題

開燈問題 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;1描述有n盞燈&#xff0c;編號為1~n&#xff0c;第1個人把所有燈打開&#xff0c;第2個人按下所有編號為2 的倍數的開關&#xff08;這些燈將被關掉&#xff09;&#xff0c;第3 個人按…

計算機科學基本理論,計算機科學的基礎知識.ppt

計算機科學的基礎知識第二章 計算機科學的基礎知識 本章學習目標&#xff1a; 數據的理解、分類與表示 計算機的基本結構與工作原理 程序設計基礎 算法基礎 2.1 數據類型 2.2 計算機內部的數據 2.3 表示數據 2.4 十進制表示法 2.5 二進制表示法 2.6 十六進制表示法 2.7 八進制表…

損壞注冊表的原因

軟件: &#xff08;1&#xff09;應用程序錯誤 &#xff08;2&#xff09;驅動程序不兼容或使用了錯誤的應用程序 &#xff08;3&#xff09;應用程序在注冊表中添加了錯誤的內容 &#xff08;4&#xff09;應用程序添加了錯誤的數據文件和應用程序之間的聯系 硬件: &#xff0…

cdockpane限制調整大小_影視后期制作小伙伴必看:使用AU對聲音質量進行調整的三大技巧...

一、增幅一般人進入AU的音頻調整界面&#xff0c;會使用圖中的旋鈕進行音量調整&#xff0c;這種操作是錯誤的&#xff0c;因為通過拖拽并不能確定調整音量的大小幅度&#xff0c;精準度極低&#xff0c;反復操作才能試出最佳音量&#xff0c;效率極低。最優方案是使用左側效果…

html5css3js文件作業,HTML5 CSS3 JavaScriptWeb前端開發自測試卷2.docx

自測試卷2一、選擇題1&#xff0e;使用標簽在網頁中成功地添加一張圖片&#xff0c;必不可少的屬性是( )。A&#xff0e;alt B&#xff0e;title C&#xff0e;src D&#xff0e;width2&#xff0e;使用CSS設置鼠標放置在鏈接上時的樣式應使用以下哪個選擇器( )。A&#xff0e;…

線程故事:Web應用程序中的ThreadLocal

本周&#xff0c;我花了一些合理的時間來消除Web應用程序中的所有ThreadLocal變量。 原因是他們造成了類加載器泄漏&#xff0c;我們不能再適當地取消部署我們的應用程序。 取消部署應用程序后&#xff0c;當GC根目錄繼續引用應用程序對象時&#xff0c;將發生類加載器泄漏。 如…

n-1位數

n-1位數 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;1描述已知w是一個大于10但不大于1000000的無符號整數&#xff0c;若w是n(n≥2)位的整數&#xff0c;則求出w的后n-1位的數。 輸入第一行為M&#xff0c;表示測試數據組數。接下來M行&…

Android之封裝好的異步網絡請求框架

1.簡介 Android中網絡請求一般使用Apache HTTP Client或者采用HttpURLConnection&#xff0c;但是直接使用這兩個類庫需要寫大量的代碼才能完成網絡post和get請求&#xff0c;而使用這個MyHttpUtils庫可以大大的簡化操作&#xff0c;它是基于HttpURLConnection&#xff0c;所有…

華潤置地php面試題_從一流到頂流|2020華潤置地與沈陽一起美好

如果用一句話來形容華潤置地進入沈陽13年的發展歷程&#xff0c;你認為是什么&#xff1f;“從優秀到卓越”。用2020年的語言你給我翻譯一下&#xff1f;“從一流到頂流”&#xff01;01/ 初識的美好猶記2007年1月&#xff0c;央企華潤置地首進沈陽&#xff0c;在大館原址呈現出…

金融工作用計算機嗎,為什么計算機專業的人想轉金融,而金融專業的想轉計算機?...

1首先兩個專業都很有前途。如果好好學IT&#xff0c;應該是走技術路線&#xff0c;30歲后逐漸開始搞些管理或者設計之類的。當然&#xff0c;繼續搞技術也沒問題。只是要不斷學習&#xff0c;因為發展很快&#xff0c;IT業自身不斷更新。很多人說IT枯燥&#xff0c;難學&#x…

Java GUI應用程序關閉陷阱

最近&#xff0c;我遇到了一個或兩個Java GUI應用程序在關閉時無法關閉的問題。 它們似乎是一個過程&#xff0c;消耗著計算機資源。 今天&#xff0c;我深入探究了問題的根源&#xff0c;這是一個我以前從未意識到的棘手問題&#xff0c;所以我想我會分享一下。 理論上&#x…

shell啟動程序腳本

#!/bin/bash#/usr/local/xxx/bin/xxxx.sh start#/usr/local/xxx/bin/startup.shfor i in find /server -name start.sh do fadirdirname $i //讀取父目錄 cd $fadir echo > nohup.out ./start.sh & sleep 2 echo "start succe…

Unity性能優化的N種武器

貼圖&#xff1a; l 控制貼圖大小&#xff0c;盡量不要超過 1024 x1024&#xff1b; l 盡量使用2的n次冪大小的貼圖&#xff0c;否則GfxDriver里會有2份貼圖&#xff1b; l 盡量使用壓縮格式減小貼圖大小&#xff1b; l 若干種貼圖合并技術&#xff1b; l 去除多余的alpha…

cmd控制屏幕光標_電腦控制手機?上班時間愉快盡情地玩手機吧!它值得您擁有!...

在現今時代&#xff0c;手機已成為人們必不可少的工具&#xff0c;有的時候甚至可以說手機比電腦方便好用多了&#xff0c;例如某些實用的APP軟件就只有手機端并沒有電腦端&#xff0c;想使用的話就得整天捧著手機盯著不放。但別忘記&#xff0c;我們大多數都是打工族&#xff…

xp系統設置鎖定計算機,系統鎖定時不關機的訣竅 給XP系統關閉計算機再加一把鎖...

很多用戶抱怨在使用電腦的過程中&#xff0c;總是經常會被瑣碎的事情打斷&#xff0c;有時候難免暫時離開電腦&#xff0c;處于便利和資料安全&#xff0c;我們往往會按下“WindowsL”來鎖定計算機。這樣&#xff0c;操作方便同時又能阻止他人亂動我們的計算機。但是如果遇到好…

ACM題目————中位數

題目描述 長為L的升序序列S&#xff0c;S[L / 2]為其中位數。 給出兩個等長升序序列S1和S2&#xff0c;求兩序列合并并排序后的中位數。 輸入 多組數據&#xff0c;每組第一行為n&#xff0c;表示兩個等長升序序列的長度。 接下來n行為升序序列S1的元素&#xff0c;再接下來n行…

Regular Exprassion--正則表達式基礎

正則表達式&#xff1a; 強大靈活的文本處理工具 語法&#xff1a; 普通字符 轉義字符 \ , \t , \n , \\ 標準字符集合&#xff08;大寫代表相反的意思&#xff09; \d 任意一個數字 \w 任意一個字母、數字、下劃線 \s 空白符&#xff…