遍历和枚举具有多线程的目录

时间:2013-07-23 19:44:39

标签: java multithreading search

我正在运行一个线程来遍历我的本地目录(没有子目录),一旦我得到一个文本文件,我就开始一个新的线程来搜索该文件中的一个单词。

以下代码有什么问题?

搜索和遍历工作正常,分开。但是当我把它放在一起时,有些东西出错了,它正在跳过一些文件(不完全是,由于多线程对象的同步没有正确发生)。

请帮帮我。

Traverse.java

    public void executeTraversing() {
            Path dir = null;
            if(dirPath.startsWith("file://")) {
                    dir = Paths.get(URI.create(dirPath));
            } else {
                    dir = Paths.get(dirPath);
            }
            listFiles(dir);
    }

    private synchronized void listFiles(Path dir) {
            ExecutorService executor = Executors.newFixedThreadPool(1);
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
                    for (Path file : stream) {
                            if (Files.isDirectory(file)) {
                                    listFiles(file);
                            } else {
                                    search.setFileNameToSearch(file);
                                    executor.submit(search);
                            }
                    }
            } catch (IOException | DirectoryIteratorException x) {
                    // IOException can never be thrown by the iteration.
                    // In this snippet, it can only be thrown by
                    // newDirectoryStream.
                    System.err.println(x);
            }
    }

Search.java

    /**
     * @param wordToSearch
     */
    public Search(String wordToSearch) {
            super();
            this.wordToSearch = wordToSearch;
    }

    public void run() {
            this.search();    
    }

    private synchronized void search() {
            counter = 0;

            Charset charset = Charset.defaultCharset();
            try (BufferedReader reader = Files.newBufferedReader(fileNameToSearch.toAbsolutePath(), charset)) {
                    // do you have permission to read this directory?
                    if (Files.isReadable(fileNameToSearch)) {
                            String line = null;
                            while ((line = reader.readLine()) != null) {
                                    counter++;
                                    //System.out.println(wordToSearch +" "+ fileNameToSearch);

                                    if (line.contains(wordToSearch)) {
                                            System.out.println("Word '" + wordToSearch
                                                            + "' found at "
                                                            + counter
                                                            + " in "
                                                            + fileNameToSearch);
                                    }
                            }
                    } else {
                            System.out.println(fileNameToSearch
                                            + " is not readable.");
                    }

            } catch (IOException x) {
                System.err.format("IOException: %s%n", x);
            }

    }

2 个答案:

答案 0 :(得分:4)

您在此处不断重复使用的此搜索实例:

search.setFileNameToSearch(file);
executor.submit(search);

虽然它的实际search()方法是同步的,但它实际上在搜索时会出现setFileNameToSearch()多次被调用的情况,这可以解释跳过。

每次都创建一个Search的新实例,然后您就不需要同步实际的search()函数。

答案 1 :(得分:2)

您正在ExecutorService方法中创建listFiles,这可能不是一个好主意:因为您可能创建了太多线程。

除此之外,你没有监控所有这些ExecutorServices的状态,当应用程序停止时,其中一些可能无法启动

相反,在开始递归之前,您应该只创建一次ExecutorService。递归结束后,在ExecutorService上调用shutdown()以等待所有任务完成

此外,您正在重用Search对象并在修改它时将其传递给多个任务,您应该为正在处理的每个文件创建一个搜索