Java中使用阻塞队列控制线程集实例

 更新时间:2015年01月15日 11:08:18   投稿:junjie  
这篇文章主要介绍了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; 
}

相关文章

  • SpringBoot整合RabbitMQ及原理

    SpringBoot整合RabbitMQ及原理

    这篇文章主要介绍了SpringBoot整合RabbitMQ及其原理分析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • Javaweb项目session超时解决方案

    Javaweb项目session超时解决方案

    这篇文章主要介绍了Javaweb项目session超时解决方案,关于解决方案分类比较明确,内容详细,需要的朋友可以参考下。
    2017-09-09
  • SpringBoot实现登录校验(JWT令牌)

    SpringBoot实现登录校验(JWT令牌)

    JWT全称为JSON Web Token,是一种用于身份验证的开放标准,本文主要介绍了SpringBoot实现登录校验(JWT令牌),具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • java使用反射给对象属性赋值的两种方法

    java使用反射给对象属性赋值的两种方法

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,下面这篇文章主要给大家介绍了关于java使用反射给对象属性赋值的两种方法,需要的朋友可以参考下
    2023-04-04
  • spring boot整合shiro安全框架过程解析

    spring boot整合shiro安全框架过程解析

    这篇文章主要介绍了spring boot整合shiro安全框架过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • SpringBoot限制接口访问频率功能实现

    SpringBoot限制接口访问频率功能实现

    最近在基于SpringBoot做一个面向普通用户的系统,为了保证系统的稳定性,防止被恶意攻击,我想控制用户访问每个接口的频率,接下来通过本文给大家介绍SpringBoot限制接口访问频率功能实现,需要的朋友可以参考下
    2023-05-05
  • 详解Struts2动态方法调用

    详解Struts2动态方法调用

    这篇文章主要介绍了详解Struts2动态方法调用,涉及调用方法的代码,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09
  • JavaWeb分页的实现代码实例

    JavaWeb分页的实现代码实例

    这篇文章主要介绍了JavaWeb分页的实现代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 玩转SpringBoot2快速整合拦截器的方法

    玩转SpringBoot2快速整合拦截器的方法

    这篇文章主要介绍了玩转SpringBoot2快速整合拦截器的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Java与C++分别用递归实现汉诺塔详解

    Java与C++分别用递归实现汉诺塔详解

    汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。本文将用Java与C++分别实现,感兴趣的可以学习一下
    2022-05-05

最新评论