Java并发:阻塞队列

对于实际编程来说,应该尽可能远离底层。

    对于多线程的问题,可以通过使用一个或多个队列以优雅且安全的方式将其形式化。生产者线程想队列插入元素,消费者线程则取出它们。使用队列,可以安全地从一个线程想另一个线程传递数据。

    下面是使用阻塞队列的案例。 

package com.hef.controller;

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

/**
 * 不需要显式的线程同步,在这个应用中,使用队列数据结构作为一种同步机制
 * 需求: 一个生成者线程递归读取目标下所有的文件; 开启多个消费者线程,每个搜索线程从队列中取出一个文件,打开它,打印所有包含关键字的行。
 * 然后取出下一个文件。使用一个技巧终止应用程序:当搜索线程取到虚拟对象的时候,将其放回并终止
 * @Date 2019/10/14
 * @Author lifei
 */
public class BlockingQuqueTest {

    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);


    public static void main(String[] args) {
        try(Scanner in = new Scanner(System.in)){
            System.out.print("Enter base directory (e.g. /opt/jdk/src): ");
            String directory = in.nextLine();
            System.out.print("Enter keyword (e.g. volatile): ");
            String keyword = in.nextLine();

            // 准备启动生产者线程
            Runnable enumerator = ()->{
                try {
                    enumerate(new File(directory));
                    // 放置一个虚拟对象到队列中
                    queue.put(DUMMY);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            };
            // 启动生产线程
            new Thread(enumerator).start();

            // 开启多个消费者线程
            for (int i=0; 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 (InterruptedException|FileNotFoundException e) {
                        e.printStackTrace();
                    }
                };
                new Thread(searcher).start();
            }
        }
    }

    /**
     * 查询文件
     * @param file
     * @param keyworld
     * @throws FileNotFoundException
     */
    public static void search(File file, String keyworld) throws FileNotFoundException {
        try(Scanner in = new Scanner(file, "UTF-8")){
            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);
                }
            }
        }
    }

    /**
     * 遍历目录下的所有文件,并将文件添加到阻塞队列中
     * 递归遍历目录
     * @param directory
     */
    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);
        }
    }
}
原创文章 161 获赞 19 访问量 6万+

猜你喜欢

转载自blog.csdn.net/hefrankeleyn/article/details/102558108