Java并发(Runnable+Thread)实现硬盘文件搜索功能

零、插播2020CSDN博客之星投票新闻

近日(1月11日-1月24日),2020CSDN博客之星评选正在火热进行中,作为码龄1年的小白有幸入选Top 200,首先很感谢CSDN官方把我选上,本来以为只是来凑热闹,看大佬们PK 。

综合过去9天大佬们战况,前10名大佬基本坐得很稳,后期出现黑马发力,势不可挡,都在冲刺Top 20,有了微妙的变化,不得不令人佩服点赞!真正的实力可以看出,文章数量不重要,更重要的是质量!一切用数据说话,如图:

截至 2021-01-20 11:50:02

看了大佬的惊人数据,与我差距甚大,不禁感慨,接下来看看我自己!

首先,很感谢每一位帮忙投票的粉丝和兄弟姐妹们,感谢您的关注和支持,经过大家上一周的共同努力,我已进入2020博客之星投票排行榜Top 100。

投票还有一周时间,进入更激烈更有悬念的阶段,希望读者们下来一周能投出您手中宝贵的票权,让我更进一步!

投票地址:https://bss.csdn.net/m/topic/blog_star2020/detail?username=charzous

或者扫码投票:

重点:每一个投票都会被记录,投了之后找Charzous帮忙也容易了(疯狂暗示投票拉票)!

比如,帮忙下载资源,或者博客一键三连,再次对每位帮我投票的粉丝表示感谢! 😊新的一年,让我们一起变得更强!

即日起到24号,每天都可以投票哦,票数越多,贡献排行榜就越靠前,我就记住你的名字啦!

24号是否能和大佬们在顶峰相见,就靠大家了哈!

一、承上启下

前一篇学习了Java并发程序设计原理之后,为了对这个部分有了更深层的理解,并运用于实际场景中,所以我找了比较实际的案例进行实践——文件搜索,简单来说,这也是电脑文件系统中的一个常见功能,用户可以通过用户名搜索文件系统中符合条件的文件。

文件搜索的程序需要用到Java并发API中的Thread类和Runnable接口,其中一些重要的内容先简单了解一下。

二、Java中的多线程

线程类Thread,有两种方式创建执行线程。

1、扩展Thread类并重载run()方法

Thread类包含了丰富的方法,在实现线程时候必须重载run方法,扩展Thread类和调用start方法创建新的线程。其他常用方法:

getId():获取Thread对象的标识符,线程整个生命周期中唯一不变的一个正整数。getName()/setName():String类型,获取或设置Thread对象名。

getPriority()/setPriority():获取或设置线程的优先级。值范围:Thread.MIN_PRIORITY~Thread.MAX_PRIORITY(1~10),创建时默认Thread.NORM_PRIORITY(5)。getState():线程对象的状态。包括:NEW(新创建)、RUNNABLE(运行中)、BLOCKED(等待锁定)、WAITING(等待)、TIME_WAITING(有时间限制等待)、THREAD(完成)。

线程在一段时间中只能处于一种状态,而且是在JVM中的状态,不能映射到操作系统的线程状态。interrupt():请求结束执行Thread对象。

interrupted():检查中断状态,清除中断标志的值。

isInterrupted():检查中断状态,不清除中断标志的值。

sleep():线程执行睡眠时间,单位毫秒。

join():暂停调用线程的执行,直到调用该方法的线程执行结束为止。

currentThread():静态方法,返回实际执行当前任务的Thread对象。

2、实现Runnable接口

可以通过线程来执行Runnable对象,更灵活更改并发程序,还可以通过不同线程使用同一个Runnable对象。

相对来说,使用Runnable接口创建线程的方法更加推荐,它只定义了run方法,是每个线程的主方法。当执行start方法启动新线程时,就会调用run方法。

三、串行文件搜索

这里分为两种版本,串行(单线程)和并发(多线程),后续可以进行比较。

1、创建公共类Result保存搜索结果

/**
 * Result.java
 * @author Charzous
 * @date 2021/1/20 11:00
 *
 */

package SearchFiles;

public class Result {
 boolean found;
 String path;

 public void setFound(boolean found){
 this.found=found;
 }

 public boolean isFound(){
 return this.found;
 }

 public void setPath(String path){
 this.path=path;
 }

 public String getPath(){
 return this.path;
 }
}

2、查找算法

算法思路简单,通过初始路径,获取文件和目录内容,并与目标文件名进行比较,相同则记录Result,算法完成;不同则递归遍历文件,直到算法完成。

/**
 *
 * SerialSearch.java
 * @author Charzous
 * @date 2021/1/20 11:15
 *
 */

package SearchFiles;

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{
 if (content.getName().equals(fileName)){
  result.setPath(content.getAbsolutePath());
  result.setFound(true);
  System.out.println("Serial Search Path: "+result.getPath());
  return;
 }
 }
 if (result.isFound())
 return;
 }
 }

 public static void main(String[] args) {
 Result result=new Result();
 File file=new File("D:\\");
 long startTime=System.currentTimeMillis();
 String fileName="maskOrder.txt";
 SerialFileSearch.searchFiles(file,fileName,result);

 if (!result.isFound())
 System.out.println("未找到该文件:"+fileName);
 else
 System.out.println("找到该文件:"+fileName+"!");
 System.out.println("查询时间:"+(System.currentTimeMillis()-startTime)+"ms");
 }
}

四、并行文件搜索(多线程)

1、创建ParallelGroupFileTask类

它实现所有用于查找文件的线程,实现Runnable接口,重载run方法,其中包括了处理目录的processDirectory方法,处理文件的processFile方法。

/**
 * ParallelGroupFileTask.java
 * @author Charzous
 * @date 2021/1/20 11:31
 *
 */
package SearchFiles;

import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;

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

 @Override
 public void run() {
 while (directories.size() > 0) {
 File file = directories.poll();
 try {
 processDirectory(file,fileName,parallelResult);//递归
 if (found) {
  System.out.println(Thread.currentThread().getName() + " has found the file");
  System.out.println("parallel search:Path :" + parallelResult.getPath());
  return;
 }
 } catch (Exception e) {
 System.out.println(Thread.currentThread().getName() + " hae been interrupted");
 }
 }
 }

 public void processDirectory(File file, String fileName, Result parallelResult) throws InterruptedException {
 File[] contents;
 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;
 }
 }
 }

 public 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;
 }

}

2、多线程算法

创建ParallelGroupFileSearch类,其中包括了存放基本路径的线程安全的列表ConcurrentLinkedQueue,然后创建新线程,数量有JVM中可用的线程数量,通过Runtime的availableProcessors方法获得。

其中,若某个线程找到目标文件,会使用interrupt方法取消其他线程的执行。具体实现代码如下:

/**
 * ParallelGroupFileSearch.java
 * @author Charzous
 * @date 2021/1/20 11:40
 *
 */
package SearchFiles;

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[] contents = file.listFiles();

 for (File content : contents) {
 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;
 }
 if (numFinished != threads.length) {
 for (Thread thread : threads)
 thread.interrupt();
 }

 }

 public static void main(String[] args) {
 Result result=new Result();
 File file=new File("D:\\");
 String fileName="maskOrder.txt";
 long startTime=System.currentTimeMillis();

 ParallelGroupFileSearch.searchFiles(file,fileName,result);

 System.out.println("查询时间:"+(System.currentTimeMillis()-startTime)+"ms");
 }

}

五、结果

1、串行(单线程)

串行版本多次测试结果用时在1900ms左右!

10次测试数据:

查询时间:1978ms 2036 1860 1926 1861 2100 1889 2030 1905 1990

2、并发(多线程)

并发版本多线程测试用时在1400ms左右!

10次测试数据:

查询时间:1441ms 1368 1258 1546 1444 1430 1490 1432 1338 1435

从简单的测试结果可以看出,并发搜索的算法速度提升明显。

这一篇通过实际的案例进行实践——文件搜索,简单来说,这也是电脑文件系统中的一个常见功能,用户可以通过用户名搜索文件系统中符合条件的文件。Runnable接口和Thread类的基本使用也有了更深的认识。在文件搜索这个案例中,学习了Java并发原理的实际应用,首先设计一种串行的版本,然后再实现并发的版本,这也是一个改进的过程。

到此这篇关于Java并发(Runnable+Thread)实现硬盘文件搜索的文章就介绍到这了,更多相关Java并发硬盘文件搜索内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中Runnable和Thread的区别分析

    Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限, 下面看例子: 复制代码 代码如下: package org.thread.demo; class MyThread extends Thread{ private String name; public MyThread(String name) { super(); this.name = name; } publ

  • java实现多线程的两种方式继承Thread类和实现Runnable接口的方法

    实现方式和继承方式有什么区别呢? *区别: *继承Thread:线程代码存放在Thread子类run方法中 *实现Runnable:线程代码存放在接口的子类的run方法中 *实现方式的好处:避免了单继承的局限性 *在定义线程时,建议使用实现方式,当然如果一个类没有继承父类,那么也可以通过继承Thread类来实现多线程 *注意:Runnable接口没有抛出异常,那么实现它的类只能是try-catch不能throws *Java对多线程的安全问题提供了专业的解决方式就是同步代码块synchroniz

  • 详解Java中Thread 和Runnable区别

    Thread 和Runnable 关系 Thread类是接口Runnable的一个实现类. public class Thread implements Runnable 源码分析 Thread Threa类运行的时候调用start()方法,源代码如下: 调用start()方法,实际运行的是start0方法,方法声明如下: private native void start0() native表明这个方法是个原生函数,即这个函数是用C/C++实现的,被编译成DLL,由Java调用. native

  • 浅析Java中Runnable和Thread的区别

    线程的起动并不是简单的调用了你的RUN方法,而是由一个线程调度器来分别调用你的所有线程的RUN方法, 我们普通的RUN方法如果没有执行完是不会返回的,也就是会一直执行下去,这样RUN方法下面的方法就不可能会执行了,可是线程里的RUN方法却不一样,它只有一定的CPU时间,执行过后就给别的线程了,这样反复的把CPU的时间切来切去,因为切换的速度很快,所以我们就感觉是很多线程在同时运行一样. 你简单的调用run方法是没有这样效果的,所以你必须调用Thread类的start方法来启动你的线程.所以你启动

  • JAVA多线程Thread和Runnable的实现

    java中只允许单一继承,但允许实现多个接口,因此第二种方法更灵活. 复制代码 代码如下: /**     * 运行继承java.lang.Thread类定义的线程     */    public void startOne() {        // 创建实例        OneThread oneThread = new OneThread();        // 启动线程ThreadA        oneThread.startThreadA();        try {    

  • Java 线程对比(Thread,Runnable,Callable)实例详解

    Java 线程对比Thread,Runnable,Callable java 使用 Thread 类代表线程,所有现场对象都必须是 Thread 类或者其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流.java 使用线程执行体来代表这段程序流. 1.继承Thread 类创建线程 启动多线程的步骤如下: (1)定义Thread 类的子类,并重写该类的run() 方法,该run() 方法的方法体就代表类线程需要完成的任务.因此把run() 方法称为线程执行体. (2)创建 Th

  • Java并发(Runnable+Thread)实现硬盘文件搜索功能

    零.插播2020CSDN博客之星投票新闻 近日(1月11日-1月24日),2020CSDN博客之星评选正在火热进行中,作为码龄1年的小白有幸入选Top 200,首先很感谢CSDN官方把我选上,本来以为只是来凑热闹,看大佬们PK . 综合过去9天大佬们战况,前10名大佬基本坐得很稳,后期出现黑马发力,势不可挡,都在冲刺Top 20,有了微妙的变化,不得不令人佩服点赞!真正的实力可以看出,文章数量不重要,更重要的是质量!一切用数据说话,如图: 截至 2021-01-20 11:50:02 看了大佬的

  • C#使用dir命令实现文件搜索功能示例

    本文实例讲述了C#使用dir命令实现文件搜索功能.分享给大家供大家参考,具体如下: 以往,我都是使用 System.IO.Directory.GetDirectories() 和 System.IO.Directory.GetFiles() 方法遍历目录搜索文件.但实际的执行效果始终差强人意,在检索多种类型文件方面不够强大,尤其是在检索特殊文件夹或遇到权限不足时会引发程序异常. 这次为朋友写了个检索图片的小程序,在仔细研究了 Process 以及 ProcessStartInfo 之后,决定利用

  • Python实现的本地文件搜索功能示例【测试可用】

    本文实例讲述了Python实现的本地文件搜索功能.分享给大家供大家参考,具体如下: 偶尔需要搜索指定文件,不想每次都在windows下面去搜索,想用代码来实现搜索,而且能够收集搜索结果,于是有了下面的代码. # -*- coding:utf-8 -*- #! python2 import os def search_file(fileNmae, path): '''search a file in target directory :param fileNmae: file to be sear

  • 硬盘文件搜索代码(ASP类)

    <%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%> <% dim st st=timer() '************************************************************* '*************搜索硬盘文件的类SearchFile ************* '*************调用方法: ************* '*************Set new

  • Java并发编程之常用的辅助类详解

    1.CountDownLatch 1.2.示例:班长锁门问题 问题描述:假如有7个同学晚上上自习,钥匙在班长手上,并且要负责锁门.班长必须要等所有人都走光了,班长才能关灯锁门.这6个同学的顺序是无序的,不知道它们是何时离开.6个同学各上各的自习,中间没有交互.假如说6个学生是普通线程,班长是主线程,如何让主线程要等一堆线程运行完了,主线程才能运行完成呢. public class CountDownLatchDemo { public static void main(String[] args

  • java并发请求下数据插入重复问题的解决方法

    目录 前言 分布式锁工具类 在过滤器实现请求拦截 总结 前言 前段时间发现数据库里经常会存在两条相同的用户数据,导致数据查询异常.查了原因,发现前端微信小程序在授权登录时,有时会出现同时发送了两条一模一样的请求(也就是常说的并发).虽然后端代码有做防重复的判断,但是避免不了并发时候的重复性操作.于是就开始考虑并发的解决方案,解决方案有很多,从拦截请求到数据库层面都可以入手. 我们采用了对请求报文生成摘要信息+Redis分布式锁的方案.运行了一段时间,功能很可靠,代码也很简洁.于是上来做下记录以便

  • Java并发工具类Future使用示例

    目录 前言 Future使用示例 FutureTask 前言 Future是一个接口类,定义了5个方法: boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws Interrupte

  • Java并发编程之关键字volatile的深入解析

    目录 前言 一.可见性 二.有序性 总结 前言 volatile是研究Java并发编程绕不过去的一个关键字,先说结论: volatile的作用: 1.保证被修饰变量的可见性 2.保证程序一定程度上的有序性 3.不能保证原子性 下面,我们将从理论以及实际的案例来逐个解析上面的三个结论 一.可见性 什么是可见性? 举个例子,小明和小红去看电影,刚开始两个人都还没买电影票,小红就先去买了两张电影票,没有告诉小明.小明以为小红没买,所以也去买了两张电影票,因为他们只有两个人,所以他们只能用两张票,这就是

  • Java中使用Thread类和Runnable接口实现多线程的区别

    使用Thread类和Runnable接口实现多线程的区别 先看两种实现方式的步骤: public class ThreadDemo{ public static void main(String[] args) { for (int i = 0; i < 5; i++) { //创建并启动由继承Thread类创建的线程 new Thread(new MyThread(),"Thread"+i).start(); //创建并启动由实现Runnable接口创建的线程 new Thre

  • VBS调用WMI遍历搜索硬盘文件并计数的方法

    多年之前写的一个VBS调用WMI来遍历搜索硬盘文件,并计数的函数,今天整理网盘,看到了,发上来 核心代码: Function wmisfile(path_sf,justcnt) 'On Error Resume Next StrComputer = "." Set ObjWMIService = GetObject("winmgmts:\\" & StrComputer & "\root\cimv2") Set FileList

随机推荐