如何组织多线程与队列一起工作?

naz*_*art 2 java queue multithreading synchronized find

我很开心,让自己陷入困境.

我需要在文件中组织多线程查找:

用户输入find(路径)和find(word);

  • 第一个线程.txt在文件夹中查找文件并将结果添加到队列中
  • 当队列有一些文件=>第二个线程开始在这个文件中找到需要查找的内容(word).
  • 如果找到成功将显示此文件的路径+此文字在文件中遇到的次数.

Qestions:

  • 我们可以使用ArrayList(或存在任何替代方案)用于几个线程的队列吗?
  • 如果队列为空怎么办,第二个线程没有启动但是等待第一个找到需要文件?
  • 我们需要使用synchronized来执行此任务并继承MultiThreadingSearch(或更好地使用组合)吗?

码:

import java.util.*;
import java.io.*;

class ArrayListOfFiles {
    private Node first, last;

    private class Node {
        String item;
        Node next;
    }

    public boolean isEmpty() {
        return first == null;
    }

    public synchronized void enqueue(String item) {
        Node oldlast = last;
        last = new Node();
        last.item = item;
        last.next = null;
        if (isEmpty())
            first = last;
        else
            oldlast.next = last;
    }

    public synchronized String dequeue() {
        String item = first.item;
        first = first.next;
        if (isEmpty())
            last = null;
        return item;
    }
}

class FolderScan extends MultiThreadingSearch implements Runnable {

    FolderScan(String path, String whatFind) {
        super(path, whatFind);
    }

    @Override
    public void run() {
        findFiles(path);
    }

    ArrayListOfFiles findFiles(String path) {
        File root = new File(path);
        File[] list = root.listFiles();
        for (File titleName : list) {
            if (titleName.isDirectory()) {
                findFiles(titleName.getAbsolutePath());
            } else {
                if (titleName.getName().toLowerCase().endsWith((".txt"))) {
                    textFiles.enqueue(titleName.getName());
                }
            }
        }

        return textFiles;
    }

}

class FileScan extends MultiThreadingSearch implements Runnable {
    Scanner scanner = new Scanner((Readable) textFiles);
    Set<String> words = new HashSet<String>();
    int matches = 0;

    FileScan(String file, String whatFind) {
        super(file, whatFind);
        Thread wordFind = new Thread();
        wordFind.start();
    }

    @Override
    public void run() {
        while (scanner.hasNext()) {
            String word = scanner.next();
            words.add(word);
        }

        if (words.contains(this.whatFind)) {
            System.out.println("File:" + this.path);
            matches++;
        }

        System.out.println(matches);
    }

}

public class MultiThreadingSearch {
    String path;
    String whatFind;

    ArrayListOfFiles textFiles;

    MultiThreadingSearch(String path, String whatFind) {
        this.path = path;
        this.whatFind = whatFind;
        this.textFiles = new ArrayListOfFiles();

        Thread pathFind = new Thread(new FolderScan(path, whatFind));
//      pathFind.start();

        if (!textFiles.isEmpty()) {
            @SuppressWarnings("unused")
            FileScan fileScan = new FileScan(textFiles.dequeue(), whatFind);
        }

    }

    // ask user about input
    public static void askUserPathAndWord() {

        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(System.in));
        String path;
        String whatFind;
        try {
            System.out.println("Please, enter a Path and Word"
                    + "(which you want to find):");
            System.out.println("Please enter a Path:");
            path = bufferedReader.readLine();
            System.out.println("Please enter a Word:");
            whatFind = bufferedReader.readLine();

            if (path != null && whatFind != null) {
                new MultiThreadingSearch(path, whatFind);
                System.out.println("Thank you!");
            } else {
                System.out.println("You did not enter anything");
            }

        } catch (IOException | RuntimeException e) {
            System.out.println("Wrong input!");
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        askUserPathAndWord();
    }
}
Run Code Online (Sandbox Code Playgroud)

Exception in thread "main" java.lang.StackOverflowError从这段代码中得到了.
怎么能解决这个任务?

谢谢你,
纳扎尔.

Nik*_*zov 5

检查BlockingQueue它完全符合您的需要.线程可以阻塞,直到其他线程将新项添加到队列中.
至于如何分解你的系统.我会做以下事情:

  • 创建用于在路径中搜索txt文件的类.它实现了Runnable.你通过pathqueue它.它搜索txt文件的路径并将它们添加到queu.
  • 创建用于搜索文件内容的类.它实现了Runnable.您传递whatFindqueue给它,它需要从队列中,并检查新的文件它的内容.

就像是:

BlockingQueue<File> queue = new LinkedBlockingQueue<File>();
String path = ...;
String whatFind = ...;
FolderScan folderScan = new FolderScan(path, queue);
FileScan fileScan = new FileScan(whatFind, queue);

Executor executor = Executors.newCachecThreadPool();
executor.execute(folderScan);
executor.execute(fileScan);
Run Code Online (Sandbox Code Playgroud)

如果要FileScan等到FolderScan向队列中添加内容,可以使用take方法:

BlockingQueue<File> queue;
File toProcess = queue.take(); // this line blocks current thread (FileScan) until someone adds new item to the queue.
Run Code Online (Sandbox Code Playgroud)