采用多线程和生产者消费者模式来实现对于一个目录以及所有子目录下的文件内容的搜索,打印出包含指定关键字的行.

  利用ArrayBlockingQueue可以方便的实现生产者和消费者,所有消费者线程共用资源ArrayBlockingQueue对象,从而实现线程安全.生产者线程搜索当前目录及子目录,并且将相应的File对象添加到队列中,消费者线程对每个File对象进行关键字的查询,如果查到头,即停止查询.

  

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * Created by Administrator on 2016/6/30.
 */
public class BlockingQueueTest {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        System.out.print("Enter base directory:");
        String directory=in.nextLine();
        System.out.println("Enter key world.");
        String keyworld=in.nextLine();
        final int FILE_QUEUE_SIZE=10;   //队列的容积
        final int SEARCH_THREADS=100;   //消费者线程数目,(进行高并发的查询)
        BlockingQueue<File>queue=new ArrayBlockingQueue<>(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,keyworld)).start();//开启消费者线程
        }
    }
}
class FileEnumerationTask implements Runnable{
    public static File DUMMY=new File("");  //定义队列到头的标记
    private BlockingQueue<File> queue;
    private File startingDirectory;

    public FileEnumerationTask(BlockingQueue<File> queue, File startingDirectory) {
        this.queue = queue;
        this.startingDirectory = startingDirectory;
    }

    @Override
    public void run() {
        try {
            enumerate(startingDirectory);
            queue.put(DUMMY);       //在队列的最后放入标记
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void enumerate(File startingDirectory) {
        File[] files=startingDirectory.listFiles();
        for(File file:files) {
            if(file.isDirectory()) {
                enumerate(file);
            }
            else {
                try {
                    queue.put(file);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
class SearchTask implements Runnable {
    private BlockingQueue<File> queue;
    private String keyworld;

    public SearchTask(BlockingQueue<File> queue, String keyworld) {
        this.queue = queue;
        this.keyworld = keyworld;
    }

    @Override
    public void run() {
        boolean done=false;
        while (!done) {
            try {
                File file=queue.take();     //线程安全的操作,取得File对象
                if(file==FileEnumerationTask.DUMMY) {
                    queue.put(file);
                    done=true;  //队列到头,不再查询
                }
                else
                    search(file);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void search(File file) {
        try {
            try(Scanner in=new Scanner(file)) {
                int lineNumber=0;
                while(in.hasNextLine()) {
                    lineNumber++;
                    String line=in.nextLine();
                    if(line.contains(keyworld)) {
                        System.out.printf("%s:%d:%s:%n",file.getPath(),lineNumber,line);
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
时间: 2024-08-04 03:10:26

采用多线程和生产者消费者模式来实现对于一个目录以及所有子目录下的文件内容的搜索,打印出包含指定关键字的行.的相关文章

多线程:生产者/消费者模式

生产者/消费者模式 实际上,很多后台服务程序并发控制的基本原理都可以归纳为生产者/消费者模式. 生产者消费问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,消费者则可以从仓库中取走产品.解决生产者/消费者问题的方法可以分为两类: 采用某种机制保护生产者和消费者之间的同步: 生产者和消费者之间建立一个管道. 第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式. 第二种管道缓冲不易控制,被传输数据对象不易于封装,实用性不强. 同步问题的核心在于:如何保证

多线程之生产者消费者模式

最近在项目中需要使用使用多线程实现一种功能,和生产者消费者模式类似,因此,学习了下生产者消费者模式的多线程实现.在生产者消费者模式中,通常有两类线程, 即若干个生产者线程和若干个消费者线程.生产者线程负责提交用户请求,消费者线程则负责处理生产者提交的任务.生产者和消费者之间则通过共享内存缓冲区进行通信. 在这里我们选择BlockingQueue做为共享内存缓冲区. 首先,我们构建生产者生产的,和消费者需要处理的数据PCData,即相关任务数据. public class PCData { pri

JAVA多线程之生产者消费者模式

一.什么是生产者消费者模式? 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力. 二.为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产

Java多线程-----实现生产者消费者模式的几种方式

   1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理, 直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力.这个阻塞队列就是用来给生产者和消费者解耦的. 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度

用Python多线程实现生产者消费者模式爬取斗图网的表情图片

什么是生产者消费者模式 某些模块负责生产数据,这些数据由其他模块来负责处理(此处的模块可能是:函数.线程.进程等).产生数据的模块称为生产者,而处理数据的模块称为消费者.在生产者与消费者之间的缓冲区称之为仓库.生产者负责往仓库运输商品,而消费者负责从仓库里取出商品,这就构成了生产者消费者模式. 生产者消费者模式的优点 解耦假设生产者和消费者分别是两个线程.如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合).如果未来消费者的代码发生变化,可能会影响到生产者的代码.

Java多线程_生产者消费者模式1

生产者消费者模型       具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品.生产消费者模式如下图.(图片来自网络,侵删!) 生产者消费者模型的实现 生产者是一堆线程,消费者是另一堆线程,内存缓冲区可以使用List数组队列,数据类型只需要定义一个简单的类就好.关键是如何处理多线程之间的协作.这其实也是多线程通信的一个范例. 在这个模型中,最关键就是内存缓冲区为空的时候消费者必须等待,而内存缓冲区满的时候,生产者

生产者消费者模式的java实现(实现二)

这次采用ReentrantLock 实现生产者消费者模式,先说下ReentrantLock,通常叫做重入锁,所谓重入就是一个线程可以再次进入已经持有锁的代码块,在内部会对重入的次数进行计数,当计数为0,则释放锁.其实synchronized关键字所代表的内置锁,也是可以重入的.但是又有几点不同: 1.ReentrantLock将加锁与解锁进行分离,可以提供更细粒度的加解锁操作,内置锁基本都是全局锁(类,对象,代码块) 2.ReentrantLock提供了定时的加锁操作,这是内置锁无法做到的. 3

反应器模式 vs 生产者消费者模式

相似点: 从结构上,反应器模式有点类似生产者消费者模式,即有一个或多个生产者将事件放入一个Queue中,而一个或多个消费者主动的从这个Queue中Poll事件来处理: 不同点: Reactor模式则并没有Queue来做缓冲,每当一个Event输入到Reactor 反应器之后,该Reactor 反应器会主动的根据不同的Event类型将其分发给对应的Request Handler来处理. 原文地址:https://www.cnblogs.com/crazymakercircle/p/9902616.

java 多线程并发系列之 生产者消费者模式的两种实现

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式. 什么是生