我正在运行一个线程来遍历我的本地目录(没有子目录),一旦我得到一个文本文件,我就开始一个新的线程来搜索该文件中的一个单词。
以下代码有什么问题?
搜索和遍历工作正常,分开。但是当我把它放在一起时,有些东西出错了,它正在跳过一些文件(不完全是,由于多线程对象的同步没有正确发生)。
请帮帮我。
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);
}
}
答案 0 :(得分:4)
您在此处不断重复使用的此搜索实例:
search.setFileNameToSearch(file);
executor.submit(search);
虽然它的实际search()方法是同步的,但它实际上在搜索时会出现setFileNameToSearch()
多次被调用的情况,这可以解释跳过。
每次都创建一个Search
的新实例,然后您就不需要同步实际的search()
函数。
答案 1 :(得分:2)
您正在ExecutorService
方法中创建listFiles
,这可能不是一个好主意:因为您可能创建了太多线程。
除此之外,你没有监控所有这些ExecutorServices
的状态,当应用程序停止时,其中一些可能无法启动
相反,在开始递归之前,您应该只创建一次ExecutorService
。递归结束后,在ExecutorService上调用shutdown()
以等待所有任务完成
此外,您正在重用Search
对象并在修改它时将其传递给多个任务,您应该为正在处理的每个文件创建一个搜索