使用多线程实现分段处理数据,多线程复制文件
@Slf4j
public class ThreadUtil {
/**
* 将数据分段使用多线程处理
*
* @param dataList 源数据
* @param threadSize 每几条数据创建一个线程
* @param threadTaskFunction 函数式接口,里面是具体处理细节
* @return
* @throws Exception
*/
public static List<Map<String, String>> getThreadTask(List<String> dataList, Integer threadSize, ThreadTaskFunction threadTaskFunction) throws Exception {
List<String> threadDataList = new ArrayList<>();
List<Map<String, String>> resultList = new ArrayList<>();
List<Callable<List<Map<String, String>>>> taskList = new ArrayList<>();
Callable<List<Map<String, String>>> task = null;
//源数据大小
int dataSize = dataList.size();
//计算需的线程数量
int threadNum = getThreadNum(dataSize, threadSize);
//创建指定线程数的线程池
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
//根据所需的线程数量划分每个线程要处理的数据
for (int i = 0; i < threadNum; i++) {
//若threadNum所需的线程数量为1,则使用一个线程处理所有数据
if (i == threadNum - 1) {
threadDataList = dataList.subList(i * threadSize, dataSize);
} else {
//为每个线程划分处理的数据区间,
// 比如:[0 * threadSize,(0 + 1) * threadSize],若 threadSize= 2,
// 第一个线程 --->[0,2]
// 第二个线程 --->[2,4]
System.out.println("i = " + i);
int endIndex = (i + 1) * threadSize;
if (endIndex > dataSize) {
endIndex = dataSize;
}
threadDataList = dataList.subList(i * threadSize, endIndex);
}
List<String> finalThreadDataList = threadDataList;
//根据划分的区间集合创建指定的任务,这里调用自定义的函数式接口设定任务
taskList.addAll(threadTaskFunction.setThreadTaskData(finalThreadDataList));
}
//执行所有的线程任务,获取任务处理结果
List<Future<List<Map<String, String>>>> futures = executorService.invokeAll(taskList);
for (Future<List<Map<String, String>>> future : futures) {
if (future != null) {
resultList.addAll(future.get());
}
}
//关闭线程池
executorService.shutdown();
return resultList;
}
/**
* 多线程复制文件
*
* @param srcFileStr 源文件路径
* @param destFileStr 目标文件路径
*/
public static void copyFile(String srcFileStr, String destFileStr, int threadNum) throws Exception {
log.info("----------多线程复制文件开始-------------");
long start = System.currentTimeMillis();
File srcFile = new File(srcFileStr);
File destFile = new File(destFileStr);
long fileSize = srcFile.length();
if (threadNum <= 0) {
threadNum = 10;
}
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
long avg = fileSize / threadNum / (1024 * 10) * 1024 * 10;
List<Callable<String>> taskList = new ArrayList<>();
Callable<String> task = null;
for (int i = 0; i < threadNum; i++) {
if (threadNum - 1 == i) {
task = setThreadTask(srcFile, destFile, i * avg, fileSize);
} else {
task = setThreadTask(srcFile, destFile, i * avg, (i + 1) * avg);
}
taskList.add(task);
}
List<Future<String>> futures = executorService.invokeAll(taskList);
for (Future<String> future : futures) {
log.info(future.get());
}
long end = System.currentTimeMillis();
log.info("----------多线程复制文件结束-------------");
log.info("耗时:{} 秒", (end - start) / 1000);
executorService.shutdown();
}
/**
* 设置线程任务
*
* @param srcFile 源文件
* @param destFile 目标文件
* @param start 开始
* @param end 结束
* @return
*/
private static Callable<String> setThreadTask(File srcFile, File destFile, Long start, Long end) {
return new Callable<String>() {
@Override
public String call() throws Exception {
RandomAccessFile rafRead = new RandomAccessFile(srcFile, "r");
RandomAccessFile rafWrite = new RandomAccessFile(destFile, "rw");
rafRead.seek(start);
rafWrite.seek(start);
byte[] b = new byte[1024 * 10];
int len = 0;
while ((len = rafRead.read(b)) != -1) {
rafWrite.write(b, 0, len);
if (rafWrite.getFilePointer() >= end) {
break;
}
}
rafWrite.close();
rafRead.close();
return Thread.currentThread().getName() + ",执行完毕!";
}
};
}
/**
* 计算所需的线程数量
*
* @param dataSize
* @param threadSize
* @return
*/
private static Integer getThreadNum(Integer dataSize, Integer threadSize) {
int threadNum = 0;
if (dataSize % threadSize == 0) {
threadNum = dataSize / threadSize;
} else {
threadNum = dataSize / threadSize + 1;
}
return threadNum;
}
}
自定义的函数式接口
@FunctionalInterface
public interface ThreadTaskFunction {
List<Callable<List<Map<String, String>>>> setThreadTaskData(List<String> threadDataList);
}