java_多线程复制目录(探索)
这个代码在统计方面是有缺陷的.(线程嵌套)的不良一面
package experiment10.exp1; /*用多线程的方法实现目录拷贝*/ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Scanner; public class ThreadsCopy { static int count = 0; public static void main(String[] args) throws Exception { Scanner scanner = new Scanner(System.in); //todo read System.out.println("输入被复制源目录名:"); String sourceDirectory = scanner.nextLine(); System.out.println("输入副本目标目录名"); String destinationDirectory = scanner.nextLine(); /*调用多线程复制函数*/ long startTime = System.currentTimeMillis(); Thread thread = new Thread(new Runnable() { @Override public void run() { try { copyDir(sourceDirectory, destinationDirectory); // System.out.println(count+"---"); } catch (IOException e) { e.printStackTrace(); } //System.out.println(count+"!!!"); } }); thread.start(); thread.join(); //System.out.println("共启用了"+count+"个线程"); //todo 这种做法主线程和次线程之间的相对执行顺序还是不明确的(比如主线程对静态变量的打印时机还是不受控的,尽管监视到的累加的最终值是不受影响的. // 很可能是我对线程嵌套的完整执行的理解不够深刻.;对join的理解不够深刻. // 目前我认为,线程嵌套的话,新开辟一个线程的语句执行完后,如果没有对应的join来阻塞(直到该线程完整执行完毕才执行下一行代码),那么如果我们想要让嵌套开辟的子线程完全回归,值得每一层配都有join了,如果不都配join,在统计开辟的线程数和运行时间上就比较头疼. //todo 相应而生的策略:先创建所有需要创建的进程,然后统一start;就解决了线程数的统计问题(统一join,就解决了时间统计的问题)(而且不会退化为单线程排队执行. /* Thread threadNew = new Thread(new Runnable() { @Override public void run() { System.out.println("共启用了"+count+"个线程"); } }); threadNew.start(); threadNew.join();*/ System.out.println("共启用了"+count+"个线程"); System.out.println("目录拷贝完成,共耗时" + (System.currentTimeMillis() - startTime) + "毫秒"); // System.out.println("over!"); } //todo 多线程嵌套递归的方式复制 /*本递归复制函数具有检查并创建新目录的能力,*/ static void copyDir(String oldPath, String newPath) throws IOException { System.out.println(count++);//testing(通过中途的内部打印来监视count的累计情况.) File file = new File(oldPath); String[] filePath = file.list();/*//当前路径下存在的目录名和文件名的数组.比较建议用list方法,不推荐用listFile方法,因为后面 要通过连接目录名来创建新目录,用字符串比较方便.*/ /*检查新目录是否存在.若不存在,则创建一个*/ if (!(new File(newPath)).exists()) { (new File(newPath)).mkdir();//创建目录 } /*遍历当前目录下的子目录和文件*/ // for (int i = 0; i < filePath.length; i++) for (String x : filePath) { /*如果这(x)是一个子目录:(执行递归)*/ if ((new File(oldPath + File.separator + x)).isDirectory()) { Thread thread = new Thread(new Runnable() { @Override public void run() { try { copyDir(oldPath + File.separator + x, newPath + File.separator + x); } catch (IOException e) { e.printStackTrace(); } } }); thread.start(); } /*如果x所指的是个文件:执行复制即可*/ if (new File(oldPath + File.separator + x).isFile()) { File source = new File(oldPath + File.separator + x); File dest = new File(newPath + File.separator + x); if (!(dest.exists())) { Files.copy(source.toPath(), dest.toPath());//创建新文件的能力 } } }//endFor //System.out.println("The replication operation has been successfully executed!"); }//endCopyFunction }
继续修改
package experiment10.exp1; import experiment9.FileName; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.List; /** * @Author xuchaoxin * @Date 12/19/2020 9:41 AM * @Version 1.0 */ public class CreatCopyPathThreads { /*本递归复制函数具有检查并创建新目录的能力,*/ /** * @param srcPath 可能是个目录,也可能是个文件 * @param desPath 当srcPath 是一个目录的时候,desPath也必须是一个目录(1.约定该参数和srcPath是相同尾缀时;2.不用关心尾缀 * 可能的参数组合包括:dir->dir;file->file;file->dir;(不可能是dir->file) * @throws IOException * @throws InterruptedException */ static void copyPath(String srcPath, String desPath) throws IOException, InterruptedException { // System.out.println(count++);//testing(通过中途的内部打印来监视count的累计情况.) File srcPathFile = new File(srcPath); File desFile = new File(desPath); /* 如果源目标是个目录,则要保证目标目录存在: */ // if (srcPathFile.isDirectory()&&!(new File(desPath)).exists()) { // (new File(desPath)).mkdir();//创建目录 // } /*分析源路径*/ if (srcPathFile.isDirectory()) { if (!(new File(desPath)).exists()) { desFile.mkdir();//创建目录 } /*遍历当前目录下的子目录和文件(即各个条目)*/ String[] filesPathString = srcPathFile.list(); for (String subItem : filesPathString) { String absoluteSrcSubItemStr = srcPath + File.separator + subItem; String absoluteDesSubItemStr = desPath + File.separator + subItem; /*直接递归:*/ copyPath(absoluteSrcSubItemStr, absoluteDesSubItemStr); }//endFor }//end if else { if (!desFile.exists()) { Files.copy(srcPathFile.toPath(), desFile.toPath()); } } //test the class public static void main(String[] args) { try { //计时开始. long startTime = System.currentTimeMillis(); copyPath(FileName.fileName11_1, "D://src"); System.out.println("单线程目录拷贝完成,共耗时" + (System.currentTimeMillis() - startTime) + "毫秒"); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }//end class
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2023-08-23 c_报错之函数参数个数不匹配/参数之间没用逗号来分隔