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
posted @   xuchaoxin1375  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2023-08-23 c_报错之函数参数个数不匹配/参数之间没用逗号来分隔
点击右上角即可分享
微信分享提示