Blocking Queue

使用队列,可以安全地从一个线程向另一个线程传递数据。

阻塞队列方法

方法

正常动作

特殊情况下的动作方法

add

添加一个元素

如果队列满,则抛出IllegalStateException 异常

element

返回队列的头元素

如果队列空,抛出NoSuchElementException异常

offer

添加一个元素并返回true

如果队列满,返回false

peek

返回队列的头元素

如果队列空,则返回null

poll

移出并返回队列的头元素

如果队列空,则返回null

put

添加一个元素

如果队列满,则阻塞

remove

移出并返回头元素

如果队列空,则抛出NoSuchElementException异常

take

移出并返回头元素

如果队列空,则阻塞

阻塞队列方法分为以下3种,取决于当队列满或者空时它们的响应方式。

  • 如果将队列当作线程管理工具来使用,将要用到put和take方法。
  • 向满的队列中添加或从空的队列移除元素时,add remove 和element操作抛出异常。
  • 在一个多线程程序中,队列会在任何时候空或满,因此一定要使用offer poll和peek方法作为替代。这些方法如果不能完成任务,只是给出一个错误提示而不会抛出异常。

poll和peek方法返回空来指示失败。因此,向这些队列插入null值时非法的。

//在100ms内在队列的尾部插入一个元素
boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);
不带超时参数时,offer和poll等效。
java.util.concurrent包提供了阻塞队列的几个变种。默认情况下,
       LinkedBlockingQueue的容量是没有上边界的,但是,也可以选择指定最大容量。
       LinkedBlockingDeque 是一个双端的版本。
       ArrayBlockingQueue 在构造时需要指定容量,并且有一个可选的参数来指定是否需要公平性。若设置了公平参数,则那么等待了最长时间的线程会优先得到处理。通常,公平性会降低性能,只有在确实非常需要时才使用它。
        PriorityBlockingQueue是一个带优先级的队列,而不是先进先出队列。元素按照它们的优先级顺序被移出。该队列是没有容量上限,但是,如果队列是空的,取元素的操作会阻塞。(有关优先级队列的详细内容参看第9章。)
        最后,DelayQueue 包含实现Delayed接口的对象:interface Delayed extends Comparable<Delayed>{
   long getDelay(TimeUnit unit); 
}
       getDelay方法返回对象的残留延迟。负值表示延迟已经结束。元素只有在延迟用完的情况下才能从DelayQueue移除。还必须实现compareTo方法。DelayQueue 使用该方法对元素进行排序。
        Java sE 7增加了一个TransferQueue接口,允许生产者线程等待,直到消费者准备就绪可以接收一个元素。 如果生产者调用q. transfer(item);
       这个调用会阻塞,直到另一个线程将元素(item)删除。LinkedTranserQueue类实现了这个接口。
       以下程序展示了如何使用阻塞队列来控制一组线程。程序在一个目录及它的所有子目录下搜索所有文件,打印出包含指定关键字的行;
package com.example.demo.bean;                                                                                                 
                                                                                                                              
import java.io.File;                                                                                                           
import java.io.IOException;                                                                                                    
import java.util.Scanner;                                                                                                      
import java.util.concurrent.ArrayBlockingQueue;                                                                                
import java.util.concurrent.BlockingQueue;                                                                                     
                                                                                                                              
public class BlockQueueTest {                                                                                                  
   private static final int FILE_QUEUE_SIZE = 10;                                                                             
                                                                                                                              
   private static final int SEARCH_THREADS = 100;                                                                             
   private static final File DUMMY = new File("");                                                                            
   //阻塞队列                                                                                                                     
   private static BlockingQueue<File> queue = new ArrayBlockingQueue<>(FILE_QUEUE_SIZE);                                      
                                                                                                                              
   private static int searchRowCount = 0;                                                                                     
   public static void main(String[] args) {                                                                                   
       try (Scanner in = new Scanner(System.in)) {                                                                            
           System.out.println("Enter base directory");                                                                        
           String directory = in.nextLine();                                                                                  
           System.out.println("Enter keyword:");                                                                              
           String keyword = in.nextLine();                                                                                    
                                                                                                                              
           Runnable enumerator = () -> {                                                                                      
               try {                                                                                                          
                   enumerate(new File(directory));                                                                            
                   queue.put(DUMMY);                                                                                          
               } catch (InterruptedException e) {                                                                             
                                                                                                                              
                                                                                                                              
               }                                                                                                              
           };                                                                                                                 
           new Thread(enumerator).start();                                                                                    
                                                                                                                              
           for (int i = 1; i < SEARCH_THREADS; i++) {                                                                         
               Runnable searcher = () -> {                                                                                    
                   try {                                                                                                      
                       boolean done = false;                                                                                  
                       while (!done) {                                                                                        
                           File file = queue.take();                                                                          
                           if (file == DUMMY) {                                                                               
                               queue.put(file);                                                                               
                               done = true;                                                                                   
                           } else {                                                                                           
                               search(file, keyword);                                                                         
                           }                                                                                                  
                                                                                                                              
                       }                                                                                                      
                   } catch (IOException e) {                                                                                  
                       e.printStackTrace();                                                                                   
                   } catch (InterruptedException e) {                                                                         
                                                                                                                              
                   }                                                                                                          
                                                                                                                              
               };                                                                                                             
               new Thread(searcher).start();                                                                                  
           }                                                                                                                  
                                                                                                                              
                                                                                                                              
                                                                                                                              
       }                                                                                                                      
                                                                                                                              
   }                                                                                                                          
                                                                                                                              
   public static void search(File file, String keyword) throws IOException{                                                   
       try(Scanner in = new Scanner(file,"UTF-8")){                                                                           
           int lineNumber = 0;                                                                                                
           while (in.hasNextLine()){                                                                                          
               lineNumber++;                                                                                                  
               searchRowCount++;                                                                                              
               String line = in.nextLine();                                                                                   
               //System.out.println( "searchRowCount \t" + searchRowCount);                                                   
               if(line.contains(keyword)){                                                                                    
                   System.out.printf("%s:%d:%s%n",file.getPath(),lineNumber,line);                                            
               }                                                                                                              
           }                                                                                                                  
       }                                                                                                                      
   }                                                                                                                          
                                                                                                                              
   public static void enumerate(File directory) throws  InterruptedException{                                                 
       File [] files = directory.listFiles();                                                                                 
       for (File file : files) {                                                                                              
           if (file.isDirectory()){                                                                                           
               enumerate(file);                                                                                               
           }else {                                                                                                            
               queue.put(file);                                                                                               
           }                                                                                                                  
       }                                                                                                                      
                                                                                                                              
   }                                                                                                                          
}