多线程之文件搜索
文件搜索是一个很简单的IO操作,单线程的文件搜索代码如下
首先定一个公共类Result,该类主要存储搜索结果,具有两个属性,found和path,found为Boolean值,判断是否查找到文件,path文找到的文件路径
package com.FileSearch;
public class Result {
private Boolean found;
private String path;
public Boolean getFound() {
return found;
}
public void setFound(Boolean found) {
this.found = found;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
接下来便是通过递归方法去查找对应的文件名称,代码如下
package com.FileSearch;
import java.io.File;
public class SerialFileSearch {
public static void searchFiles(File file, String fileName, Result result) {
File[] contents;
contents = file.listFiles();
if((contents == null) || (contents.length == 0)){
return ;
}
for(File content : contents) {
if(content.isDirectory()) {
searchFiles(content, fileName, result);
} else {
// System.out.println("current content is "+content);
if(content.getName().equals(fileName)) {
result.setPath(content.getAbsolutePath());
result.setFound(true);
System.out.printf("Serial Search: Path: %s%n",
result.getPath());
return ;
}
}
if(result.getFound()) {
return ;
}
}
}
}
现在,我们加上启动类
package com.FileSearch;
import java.io.File;
public class Main {
public static void main(String[] args) {
Result result = new Result();
result.setFound(false);
File file = new File("/media/");
long start = System.currentTimeMillis();
SerialFileSearch.searchFiles(file,"测试文件.txt",result);
long end = System.currentTimeMillis();
System.out.println("单线程执行耗时: "+(end - start)+"ms");
}
}
上述的代码是对每个目录依次搜索,因此在多线程并发版本中,可以考虑为每一个需要搜索的目录创建一个线程的方法,考虑到I/O操作中一次只有一个线程可以读取磁盘,所以在这里使用和JVM可用内核数相同的线程数。
在这个方法中,通过ConcurrentLinkedQueue(一个可以在并发应用程序中使用的队列Queue接口实现)用来存储初始路径所包含的目录,并创建和JVM可用处理器相同数量的线程,每个线程将从队列中获取一条路径,并处理该目录及其对应的子目录中的文件。如果其中的一个线程找到的正在查找的文件,终止该线程,并通过interrupt()方法结束其他线程的执行。
在这里,通过新建PrallelGroupFileTask类,该去实现用于查找文件的线程,该类实现了Runnable接口并且拥有四个内部属性fileName,File对象的ConcurrentLinkedQueue的directories,用于存放要处理的目录列表, Result对象的parallelResult用于存储搜索结果,名为found的boolean属性,标记是否发现了正在寻找的文件信息,代码如下
import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ParallelGroupFileTask implements Runnable {
private final String fileName;
private final ConcurrentLinkedQueue<File> directories;
private final Result parallelResult;
private boolean found;
//构造函数初始化所有的属性
public ParallelGroupFileTask(String fileName, ConcurrentLinkedQueue<File> directories, Result parallelResult) {
this.fileName = fileName;
this.directories = directories;
this.parallelResult = parallelResult;
this.found = false;
}
@Override
public void run() {
while(directories.size() > 0){
File file = directories.poll(); //取出目录
try{
processDirectory(file, fileName, parallelResult);
if(found) {
System.out.printf("%s has found the file%n",Thread.currentThread().getName());
System.out.printf("Parallel Search: Path : %s%n", parallelResult.getPath());
return ;
}
} catch (InterruptedException e) {
System.out.printf("%s has been interrupted%n", Thread.currentThread().getName());
}
}
}
//大致的搜索过程和之前的代码一样,
private void processDirectory(File file, String fileName, Result parallelResult) throws InterruptedException {
File[] contents = file.listFiles();
if((contents == null) || (contents.length == 0)) {
return ;
}
for(File content : contents) {
if(content.isDirectory()) {
processDirectory(content, fileName, parallelResult);
if(Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
if(found) {
return ;
}
} else {
processFile(content,fileName,parallelResult);
if(Thread.currentThread().isInterrupted()){
throw new InterruptedException();
}
if(found){
return ;
}
}
}
}
//文件名称对比函数而以
private void processFile(File content, String fileName, Result parallelResult) {
if(content.getName().equals(fileName)) {
parallelResult.setPath(content.getAbsolutePath());
this.found = true;
}
}
public boolean getFound() {
return found;
}
}
通过新建一个类ParallelGroupFIleSearch来创建线程并辅助算法完成,代码设计如下
import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ParallelGroupFileSearch {
public static void searchFiles(File file, String fileName, Result parallelResult){
ConcurrentLinkedQueue<File> directories = new ConcurrentLinkedQueue<>();
File[] conients = file.listFiles();
for(File content: conients) {
if(content.isDirectory()) {
directories.add(content);
}
}
int numThreads = Runtime.getRuntime().availableProcessors(); //获取可用的线程数量
Thread[] threads = new Thread[numThreads];
ParallelGroupFileTask[] tasks = new ParallelGroupFileTask[numThreads];
for(int i=0;i<numThreads; i++) { //写入数组中
tasks[i] = new ParallelGroupFileTask(fileName , directories , parallelResult);
threads[i] = new Thread(tasks[i]);
threads[i].start();
}
boolean finish = false;
int numFinished = 0;
while(!finish) {
numFinished = 0;
for(int i=0; i<threads.length; i++) {
if(threads[i].getState() == Thread.State.TERMINATED) {
numFinished++;
if(tasks[i].getFound()) {
finish = true;
}
}
}
if(numFinished == threads.length) { //当所有的线程都执行完,则停止
finish = true;
}
}
//如果numFinished比length小,则证明查找到文件
//取消全部进程
if(numFinished != threads.length) {
for(Thread thread : threads) {
thread.interrupt();
}
}
}
}
最后启动类如下
import java.io.File;
public class Main {
public static void main(String[] args) {
Result result = new Result();
result.setFound(false);
File file = new File("/media/");
long start = System.currentTimeMillis();
ParallelGroupFileSearch.searchFiles(file,"测试文件.txt",result);
long end = System.currentTimeMillis();
System.out.println("多线程执行耗时: "+(end - start)+"ms");
}
}
以上就是所线程文件搜索的整个内容,测试完之后发现的确比单线程快很多啊!!!