今天想练习一下多线程方面的东西,就写了一个多线程的Copy文件的小东西,发上来有什么不足请大家指正。
MultiThreadCopy .java
package com.copy.thread;
import java.io.File;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 多线程Copy文件
* __ __
* / \~~~/ \
* ,----( .. )
* / \__ __/
* /| (\ |(
*^ \ /___\ /\ |
* |__| |__|-"
*
* 类描述:
* @Description: TODO
* @author Levin
* @since JDK 1.7
* @date 2016年10月10日 下午5:32:29
*/
public class MultiThreadCopy extends FileUtils {
private static Queue<FileEvent> queue = new LinkedBlockingQueue<>();
public static void main(String[] args) {
String srcPath = "E:\\test\\";
String desPath = "F:\\08";
if (isExists(srcPath) && isExists(desPath)) {
// 来源路径为文件,目标路径为文件夹
if (isFile(srcPath) && isDirectory(desPath)) {
reflectStr(desPath, desPath.endsWith(File.separator) ? desPath + new File(srcPath).getName()
: desPath + File.separator + new File(srcPath).getName());
queue.add(new FileEvent().setSrcFile(srcPath).setDesFile(desPath));
}
// 来源路径为文件夹,目标路径为文件夹
if (isDirectory(srcPath) && isDirectory(desPath)) {
File srcfile = new File(srcPath);
String[] files = srcfile.list();
reflectStr(srcPath, srcPath.endsWith(File.separator) ? srcPath : srcPath + File.separator);
reflectStr(desPath, desPath.endsWith(File.separator) ? desPath : desPath + File.separator);
for (String file : files) {
if (isFile(srcPath + file)) {
queue.add(new FileEvent().setSrcFile(srcPath + file)
.setDesFile(desPath + new File(file).getName()));
}
}
}
if (isDirectory(srcPath) && isFile(desPath)) {
System.err.println("不能从一个目录复制到一个单独文件中");
System.exit(0);
}
} else {
System.err.println("srcPath:" + srcPath);
}
CountDownLatch countDownLatch = new CountDownLatch(queue.size());
ExecutorService executorService = Executors.newFixedThreadPool(30);
for (int i = 0; i < 5; i++) {
executorService.execute(new CopyFileThread(queue, true, countDownLatch));
}
try {
long startTime = System.currentTimeMillis();
countDownLatch.await();
long endTime = System.currentTimeMillis();
System.out.println("线程结束耗时:" + String.valueOf(endTime - startTime));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
CopyFileThread.java
package com.download.thread;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
/**
*
* __ __
* / \~~~/ \
* ,----( .. )
* / \__ __/
* /| (\ |(
*^ \ /___\ /\ |
* |__| |__|-"
*
* 类描述:
* @Description: TODO
* @author xLw
* @since JDK 1.7
* @date 2016年10月10日 下午5:23:10
*/
public class CopyFileThread implements Runnable {
private static Queue<FileEvent> queue;
// 是否覆盖目标文件
private boolean overlay;
private CountDownLatch countDownLatch;
public CopyFileThread(Queue<FileEvent> queue, boolean overlay, CountDownLatch countDownLatch) {
CopyFileThread.queue = queue;
this.overlay = overlay;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
while (!queue.isEmpty()) {
synchronized (queue) {
FileEvent event = queue.poll();
if (event == null && countDownLatch.getCount() != 0) {
queue.notifyAll();
break;
}
synchronized (event) {
String srcFile = event.getSrcFile();
String destFile = event.getDesFile();
if (overlay) {
new File(destFile).delete();
}
int byteread = 0; // 读取的字节数
// 传输总量
long sumDesBytes = 0;
try (InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);) {
byte[] buffer = new byte[1024];
while ((byteread = in.read(buffer)) != -1) {
out.write(buffer, 0, byteread);
sumDesBytes += byteread;
try {
// Copy完成跳出循环
if (sumDesBytes == event.getSrcBytes()) {
break;
} else {
if (countDownLatch.getCount()>1) {
queue.notifyAll();
queue.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
countDownLatch.countDown();
queue.notifyAll();
}
}
}
}
}
}
FileUtils.java
package com.download.thread;
import java.io.File;
import java.lang.reflect.Field;
public class FileUtils {
FileUtils() {
}
/**
* 反射修改String值
* @Title: reflectStr
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param oldStr
* @param newStr
* @author Levin
*/
public static void reflectStr(String oldStr, String newStr) {
try {
Field f = oldStr.getClass().getDeclaredField("value");
f.setAccessible(true);
f.set(oldStr, newStr.toCharArray());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文件是否存在
* @Title: isExists
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param file
* @return
* @author Levin
*/
public static boolean isExists(String file) {
return file != null && new File(file).exists();
}
/**
* File是否文件夹
* @Title: isDirectory
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param file
* @return
* @author Levin
*/
public static boolean isDirectory(String file) {
return new File(file).isDirectory();
}
/**
* File是否为文件
* @Title: isFile
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param file
* @return
* @author Levin
*/
public static boolean isFile(String file) {
return new File(file).isFile();
}
}
FileEvent.java
package com.download.thread;
import java.io.File;
/**
* 存放文件参数
* __ __
* / \~~~/ \
* ,----( .. )
* / \__ __/
* /| (\ |(
*^ \ /___\ /\ |
* |__| |__|-"
*
* 类描述:
* @Description: TODO
* @author Levin
* @since JDK 1.7
* @date 2016年10月10日 下午5:33:41
*/
public class FileEvent {
//源路径地址
private String srcFile;
//目标路径地址
private String desFile;
// TODO 考虑添加进度条功能扩展字段
private long srcBytes;
// TODO 考虑添加进度条功能扩展字段
private long desBytes;
public String getSrcFile() {
return srcFile;
}
public FileEvent setSrcFile(String srcFile) {
this.srcFile = srcFile;
this.srcBytes = new File(srcFile).length();
return this;
}
public String getDesFile() {
return desFile;
}
public FileEvent setDesFile(String desFile) {
this.desFile = desFile;
this.desBytes = new File(desFile).length();
return this;
}
public long getSrcBytes() {
return srcBytes;
}
public long getDesBytes() {
return desBytes;
}
}