国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > php教程 > java中queue的使用

java中queue的使用

来源:程序员人生   发布时间:2017-02-27 10:21:02 阅读次数:6576次

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!


Queue接口与List、Set同1级别,都是继承了Collection接口。LinkedList实现了Queue接 口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可使用。BlockingQueue 继承了Queue接口。

 

队列是1种数据结构.它有两个基本操作:在队列尾部加人1个元素,和从队列头部移除1个元素就是说,队列以1种先进先出的方式管理数据,如果你试图向1个 已满了的阻塞队列中添加1个元素或是从1个空的阻塞队列中移除1个元索,将致使线程阻塞.在多线程进行合作时,阻塞队列是很有用的工具。工作者线程可 以定期地把中间结果存到阻塞队列中而其他工作者线线程把中间结果取出并在将来修改它们。队列会自动平衡负载。如果第1个线程集运行得比第2个慢,则第2个 线程集在等待结果时就会阻塞。如果第1个线程集运行得快,那末它将等待第2个线程集遇上来。下表显示了jdk1.5中的阻塞队列的操作:

 

add        增加1个元索                     如果队列已满,则抛出1个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素    如果队列为空,则抛出1个NoSuchElementException异常
element  返回队列头部的元素             如果队列为空,则抛出1个NoSuchElementException异常
offer       添加1个元素并返回true       如果队列已满,则返回false
poll         移除并返问队列头部的元素    如果队列为空,则返回null
peek       返回队列头部的元素             如果队列为空,则返回null
put         添加1个元素                      如果队列满,则阻塞
take        移除并返回队列头部的元素     如果队列为空,则阻塞

 

remove、element、offer 、poll、peek 实际上是属于Queue接口。 

 

阻塞队列的操作可以根据它们的响应方式分为以下3类:aad、removee和element操作在你试图为1个已满的队列增加元素或从空队列获得元素时 抛出异常。固然,在多线程程序中,队列在任什么时候间都可能变成满的或空的,所以你可能想使用offer、poll、peek方法。这些方法在没法完成任务时 只是给出1个出错示而不会抛出异常。

 

注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的。

 

还有带超时的offer和poll方法变种,例如,下面的调用:
boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);
尝试在100毫秒内向队列尾部插入1个元素。如果成功,立即返回true;否则,当到达超时进,返回false。一样地,调用:
Object head = q.poll(100, TimeUnit.MILLISECONDS);
如果在100毫秒内成功地移除队列头元素,则立即返回头元素;否则在到达超时时,返回null。

 

最后,我们有阻塞操作put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。

 

java.ulil.concurrent包提供了阻塞队列的4个变种。默许情况下,LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎样会受阻呢),但是也能够选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。


ArrayBlockingQueue在构造时需要指定容量, 并可以选择是不是需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 到达这类公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。


PriorityBlockingQueue是1个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了1下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList1样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图履行添加操作可能会致使 OutOfMemoryError),但是如果队列为空,那末取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。


最后,DelayQueue(基于PriorityQueue来实现的)是1个寄存Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当1个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回1个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。 下面是延迟接口:

Java代码
  1. public interface Delayed extends Comparable<Delayed>  
  2.      long getDelay(TimeUnit unit);  
  3.  

放入DelayQueue的元素还将要实现compareTo方法,DelayQueue使用这个来为元素排序。

 

下面的实例展现了如何使用阻塞队列来控制线程集。程序在1个目录及它的所有子目录下搜索所有文件,打印出包括指定关键字的文件列表。从下面实例可以看出,使用阻塞队列两个显著的好处就是:多线程操作共同的队列时不需要额外的同步,另外就是队列会自动平衡负载,即那边(生产与消费两边)处理快了就会被阻塞掉,从而减少两边的处理速度差距。下面是具体实现:

Java代码
  1. public class BlockingQueueTest  
  2.     public static void main(String[] args)  
  3.         Scanner in new Scanner(System.in);  
  4.         System.out.print("Enter base directory (e.g. /usr/local/jdk5.0/src): ");  
  5.         String directory in.nextLine();  
  6.         System.out.print("Enter keyword (e.g. volatile): ");  
  7.         String keyword in.nextLine();  
  8.   
  9.         final int FILE_QUEUE_SIZE 10;// 阻塞队列大小  
  10.         final int SEARCH_THREADS 100;// 关键字搜索线程个数  
  11.   
  12.         // 基于ArrayBlockingQueue的阻塞队列  
  13.         BlockingQueue<File> queue new ArrayBlockingQueue<File>(  
  14.                 FILE_QUEUE_SIZE);  
  15.   
  16.         //只启动1个线程来搜索目录  
  17.         FileEnumerationTask enumerator new FileEnumerationTask(queue,  
  18.                 new File(directory));  
  19.         new Thread(enumerator).start();  
  20.           
  21.         //启动100个线程用来在文件中搜索指定的关键字  
  22.         for (int 1; <= SEARCH_THREADS; i++)  
  23.             new Thread(new SearchTask(queue, keyword)).start();  
  24.      
  25.  
  26. class FileEnumerationTask implements Runnable  
  27.     //哑元文件对象,放在阻塞队列最后,用来标示文件已被遍历完  
  28.     public static File DUMMY new File("");  
  29.   
  30.     private BlockingQueue<File> queue;  
  31.     private File startingDirectory;  
  32.   
  33.     public FileEnumerationTask(BlockingQueue<File> queue, File startingDirectory)  
  34.         this.queue queue;  
  35.         this.startingDirectory startingDirectory;  
  36.      
  37.   
  38.     public void run()  
  39.         try  
  40.             enumerate(startingDirectory);  
  41.             queue.put(DUMMY);//履行到这里说明指定的目录下文件已被遍历完  
  42.         catch (InterruptedException e)  
  43.          
  44.      
  45.   
  46.     // 将指定目录下的所有文件以File对象的情势放入阻塞队列中  
  47.     public void enumerate(File directory) throws InterruptedException  
  48.         File[] files directory.listFiles();  
  49.         for (File file files)  
  50.             if (file.isDirectory())  
  51.                 enumerate(file);  
  52.             else  
  53.                 //将元素放入队尾,如果队列满,则阻塞  
  54.                 queue.put(file);  
  55.          
  56.      
  57.  
  58. class SearchTask implements Runnable  
  59.     private BlockingQueue<File> queue;  
  60.     private String keyword;  
  61.   
  62.     public SearchTask(BlockingQueue<File> queue, String keyword)  
  63.         this.queue queue;  
  64.         this.keyword keyword;  
  65.      
  66.   
  67.     public void run()  
  68.         try  
  69.             boolean done false;  
  70.             while (!done)  
  71.                 //取出队首元素,如果队列为空,则阻塞  
  72.                 File file queue.take();  
  73.                 if (file == FileEnumerationTask.DUMMY)  
  74.                     //取出来后重新放入,好让其他线程读到它时也很快的结束  
  75.                     queue.put(file);  
  76.                     done true;  
  77.                 else  
  78.                     search(file);  
  79.              
  80.         catch (IOException e)  
  81.             e.printStackTrace();  
  82.         catch (InterruptedException e)  
  83.          
  84.      
  85.     public void search(File file) throws IOException  
  86.         Scanner in new Scanner(new FileInputStream(file));  
  87.         int lineNumber 0;  
  88.         while (in.hasNextLine())  
  89.             lineNumber++;  
  90.             String line in.nextLine();  
  91.             if (line.contains(keyword))  
  92.                 System.out.printf("%s:%d:%s%n", file.getPath(), lineNumber,  
  93.                         line);  
  94.          
  95.         in.close();  
  96.      
  97.  

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生