Java阻塞佇列執行緒集控制的實現
佇列以一種先進先出的方式管理資料。如果你試圖向一個已經滿了的阻塞佇列中新增一個元素,或是從一個空的阻塞佇列中移除一個元素,將導致執行緒阻塞。在多執行緒進行合作時,阻塞佇列是很有用的工具。工作者執行緒可以定期的把中間結果存到阻塞佇列中。而其他工作者執行緒把中間結果取出並在將來修改它們。佇列會自動平衡負載。如果第一個執行緒集執行的比第二個慢,則第二個執行緒集在等待結果時就會阻塞。如果第一個執行緒集執行的快,那麼它將等待第二個執行緒集趕上來。
下面的程式展示瞭如何使用阻塞佇列來控制執行緒集。程式在一個目錄及它的所有子目錄下搜尋所有檔案,列印出包含指定關鍵字的檔案列表。
java.util.concurrent包提供了阻塞佇列的4個變種:LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue和DelayQueue。我們用的是ArrayBlockingQueue。ArrayBlockingQueue在構造時需要給定容量,並可以選擇是否需要公平性。如果公平引數被設定了,等待時間最長的執行緒會優先得到處理。通常,公平性會使你在效能上付出代價,只有在的確非常需要的時候再使用它。
生產者執行緒列舉在所有子目錄下的所有檔案並把它們放到一個阻塞佇列中。這個操作很快,如果佇列沒有設上限的話,很快它就包含了沒有找到的檔案。
我們同時還啟動了大量的搜尋執行緒。每個搜尋執行緒從佇列中取出一個檔案,開啟它,列印出包含關鍵字的所有行,然後取出下一個檔案。我們使用了一個小技巧來在工作結束後終止執行緒。為了發出完成訊號,列舉執行緒把一個虛擬物件放入佇列。(這類似於在行李輸送帶上放一個寫著“最後一個包”的虛擬包。)當搜尋執行緒取到這個虛擬物件時,就將其放回並終止。
注意,這裡不需要人任何顯示的執行緒同步。在這個程式中,我們使用佇列資料結構作為一種同步機制。
import java.io.*; import java.util.*; import java.util.concurrent.*; public class BlockingQueueTest { public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.print("Enter base directory (e.g. /usr/local/jdk1.6.0/src): "); String directory = in.nextLine(); System.out.print("Enter keyword (e.g. volatile): "); String keyword = in.nextLine(); final int FILE_QUEUE_SIZE = 10; final int SEARCH_THREADS = 100; BlockingQueue<File> queue = new ArrayBlockingQueue<File>(FILE_QUEUE_SIZE); FileEnumerationTask enumerator = new FileEnumerationTask(queue, new File(directory)); new Thread(enumerator).start(); for (int i = 1; i <= SEARCH_THREADS; i++) new Thread(new SearchTask(queue, keyword)).start(); } } /** * This task enumerates all files in a directory and its subdirectories. */ class FileEnumerationTask implements Runnable { /** * Constructs a FileEnumerationTask. * @param queue the blocking queue to which the enumerated files are added * @param startingDirectory the directory in which to start the enumeration */ public FileEnumerationTask(BlockingQueue<File> queue, File startingDirectory) { this.queue = queue; this.startingDirectory = startingDirectory; } public void run() { try { enumerate(startingDirectory); queue.put(DUMMY); } catch (InterruptedException e) { } } /** * Recursively enumerates all files in a given directory and its subdirectories * @param directory the directory in which to start */ public void enumerate(File directory) throws InterruptedException { File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) enumerate(file); else queue.put(file); } } public static File DUMMY = new File(""); private BlockingQueue<File> queue; private File startingDirectory; } /** * This task searches files for a given keyword. */ class SearchTask implements Runnable { /** * Constructs a SearchTask. * @param queue the queue from which to take files * @param keyword the keyword to look for */ public SearchTask(BlockingQueue<File> queue, String keyword) { this.queue = queue; this.keyword = keyword; } public void run() { try { boolean done = false; while (!done) { File file = queue.take(); if (file == FileEnumerationTask.DUMMY) { queue.put(file); done = true; } else search(file); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { } } /** * Searches a file for a given keyword and prints all matching lines. * @param file the file to search */ public void search(File file) throws IOException { Scanner in = new Scanner(new FileInputStream(file)); int lineNumber = 0; while (in.hasNextLine()) { lineNumber++; String line = in.nextLine().trim(); if (line.contains(keyword)) System.out.printf("%s:%d %s%n", file.getPath(), lineNumber, line); } in.close(); } private BlockingQueue<File> queue; private String keyword; }
相關文章
- java多執行緒:執行緒池原理、阻塞佇列Java執行緒佇列
- Java BlockingQueue 阻塞佇列[用於多執行緒]JavaBloC佇列執行緒
- 執行緒池的阻塞佇列的理解執行緒佇列
- 深入淺出Java多執行緒(十三):阻塞佇列Java執行緒佇列
- 多執行緒程式設計-分析阻塞佇列的原始碼實現執行緒程式設計佇列原始碼
- java多執行緒8:阻塞佇列與Fork/Join框架Java執行緒佇列框架
- Python實現執行緒安全佇列Python執行緒佇列
- 阻塞佇列一——java中的阻塞佇列佇列Java
- 探討阻塞佇列和執行緒池原始碼佇列執行緒原始碼
- 原始碼剖析ThreadPoolExecutor執行緒池及阻塞佇列原始碼thread執行緒佇列
- 最全java多執行緒總結3——瞭解阻塞佇列和執行緒安全集合不Java執行緒佇列
- Java併發——阻塞佇列集(上)Java佇列
- Java併發——阻塞佇列集(下)Java佇列
- Java 阻塞佇列(BlockingQueue)的內部實現原理Java佇列BloC
- java執行緒池-工作佇列workQueueJava執行緒佇列
- 執行緒安全佇列(使用互斥鎖進行實現)執行緒佇列
- java 執行緒池執行緒忙碌且阻塞佇列也滿了時給一個拒接的詳細報告Java執行緒佇列
- Java中的阻塞佇列Java佇列
- python多執行緒中訊息佇列如何實現?Python執行緒佇列
- 多執行緒系列(十三) -一文帶你搞懂阻塞佇列執行緒佇列
- 多執行緒,執行緒類三種方式,執行緒排程,執行緒同步,死鎖,執行緒間的通訊,阻塞佇列,wait和sleep區別?執行緒佇列AI
- 主佇列&主執行緒佇列執行緒
- Java幾種執行緒池及任務佇列Java執行緒佇列
- 佇列、阻塞佇列佇列
- Java多執行緒的實現Java執行緒
- 封裝一個阻塞佇列,輕鬆實現排隊執行任務功能!封裝佇列
- Java阻塞佇列中的異類,SynchronousQueue底層實現原理剖析Java佇列
- Java 執行緒池中的執行緒複用是如何實現的?Java執行緒
- iOS 多執行緒--GCD 序列佇列、併發佇列以及同步執行、非同步執行iOS執行緒GC佇列非同步
- java執行緒實現方式Java執行緒
- 執行緒池中的最大執行緒數、核心執行緒數和佇列大小的合理設定執行緒佇列
- 多執行緒學習-Disruptor佇列執行緒佇列
- SpringBoot執行緒池和Java執行緒池的實現原理Spring Boot執行緒Java
- 自己動手實現一個阻塞佇列佇列
- Java中實現執行緒的方式Java執行緒
- Java多執行緒學習(2)執行緒控制Java執行緒
- JAVA中常見的阻塞佇列詳解Java佇列
- 從0到1實現自己的阻塞佇列(上)佇列
- java效能調優記錄(執行緒阻塞)Java執行緒