首先,用到的线程类有CountDownLatch。进行子线程的计数的。子线程中run最后面调用countDownLatch.countDown();方法,该子线程执行完后便减一,主线程中子线程的start后调用cDownLatch.await();方法,实现主线程等待并发子线程。
以下代码是实现多线程进行一个文件的读写,相当于复制了。目的是为实现多线程并发,虽然速度上还有点欠缺。
先是主程序代码
package com.filethread;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
public class ReadFileMain {
static FileThread[] fThread;
static long startTime;
final static String OUT_FILE_NAME = "C:\\Users\\dandan\\Desktop\\卑鄙的我2.神偷奶爸2.DVD中字-cut.rmvb";
/**
* @param args
*/
public static void main(String[] args) {
final int DOWN_THREAD_NUM = 4;
final String READ_FILE = "C:\\Users\\dandan\\Desktop\\svn\\卑鄙的我2.神偷奶爸2.DVD中字-cut.rmvb";
InputStream[] isArrInputStreams = new InputStream[DOWN_THREAD_NUM];
RandomAccessFile[] outArrAccessFiles = new RandomAccessFile[DOWN_THREAD_NUM];
try {
isArrInputStreams[0] = new FileInputStream(READ_FILE);
long fileLen = getFileLength(new File(READ_FILE));
System.out.println("文件的大小" + fileLen);
//以输出文件名创建第一个RandomAccessFile输出流
outArrAccessFiles[0] = new RandomAccessFile(OUT_FILE_NAME, "rw");
//创建一个与文件相同大小的空文件
for (int i = 0; i < fileLen / 1024; i++) {
try {
outArrAccessFiles[0].write(1024);
// System.out.println(i+ "------" + fileLen / 1024 + "相差:" + (fileLen / 1024 - i));
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
//每线程应该读取的字节数
long numPerthread = fileLen / DOWN_THREAD_NUM;
startTime = System.currentTimeMillis();
System.out.println(new SimpleDateFormat("yy-MM-DD HH:MM:SS").format(new Date()));
//整个文件整除后剩下的余数
long end = fileLen % DOWN_THREAD_NUM;
fThread = new FileThread[DOWN_THREAD_NUM];
CountDownLatch cDownLatch = new CountDownLatch(DOWN_THREAD_NUM);
for (int i = 0; i < DOWN_THREAD_NUM; i++) {
FileThread f2 = null;
//为每个线程打开一个输入流、一个RandomAccessFile对象,
//让每个线程分别负责读取文件的不同部分。
if (i != 0) {
isArrInputStreams[i] = new FileInputStream(READ_FILE);
//以指定输出文件创建多个RandomAccessFile对象
outArrAccessFiles[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");
}
if (i == DOWN_THREAD_NUM - 1) {
//最后一个线程读取指定numPerThred+left个字节
f2 = new FileThread(i * numPerthread, (i+1) * numPerthread + end,
isArrInputStreams[i], outArrAccessFiles[i],cDownLatch);
}else {
//每个线程负责读取一定的numPerThred个字节
f2 = new FileThread(i * numPerthread, (i + 1) * numPerthread,
isArrInputStreams[i], outArrAccessFiles[i],cDownLatch);
}
f2.start();
fThread[i] = f2;
}
/**
//判断所有子线程是否执行完毕,
int size = fThread.length;
// while(true){
for (int i = 0; i < size;) {
if (fThread[i] != null && fThread[i].getState() == Thread.State.TERMINATED) {
fThread[i] = null;size--;
}
if(fThread[i] != null && fThread[i].getState() == Thread.State.RUNNABLE)
System.out.println(fThread[i].getId() + "存活中");
if(size == 0)
warrting();break;
}
// }
*/
try {
cDownLatch.await();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
warrting();
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
public static void warrting() {
System.out.println("开始读取:时间---" + ReadFileMain.startTime);
long endTime = System.currentTimeMillis();
System.out.println("读取完毕:时间---" + endTime);
System.out.println("耗时:" + (endTime - ReadFileMain.startTime));
System.out.println(new File(ReadFileMain.OUT_FILE_NAME).length());
System.out.println(new SimpleDateFormat("yy-MM-DD HH:MM:SS").format(new Date()));
}
public static long getFileLength(File file) {
// long length = 0;
// //获取文件的长度
// long size = file.length();
// length = size;
// return length;
return file.length();
}
}
下面是子线程
下面是子线程
package com.filethread;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
public class FileThread extends Thread {
/**
* 十个线程读取一个文本文件
* 创建一个线程类,读取文件,读取方法中,返回读取到的位置,下一个线程继续时读取上一个线程读取到的末尾处。
*/
//定义字节数组(取水的竹筒)的长度
private final int BUFF_LEN = 1023;
//定义读取的起始点 //定义读取的结束点
private long start,end;
//读取文件对应的输入流
private InputStream iStream;
//将读取到的字节输出到raf中
private RandomAccessFile rat;
CountDownLatch countDownLatch;
//构造器,传入输入流,输出流和读取起始点、结束点
public FileThread(long start,long end,InputStream is,RandomAccessFile rat,CountDownLatch cd){
//输出该线程负责读取的字节位置
System.out.println(start + "***********" + end);
this.start = start;
this.end = end;
this.iStream = is;
this.rat = rat;
this.countDownLatch = cd;
}
public void run() {
System.out.println(this.getId() + "----" + System.currentTimeMillis() + "++++" +
new Date());
try {
iStream.skip(start);
rat.seek(start);
//定义读取输入流内容的的缓存数组(竹筒)
byte[] buff = new byte[BUFF_LEN];
//本线程负责读取文件的大小
long contenleng = end - start;
//定义最多需要读取几次就可以完成本线程的读取
long tim = contenleng / BUFF_LEN + 4;
//实际读取的字节数
int hasRead = 0;
for (int i = 0; i < tim; i++) {
hasRead = iStream.read(buff);
//如果读取的字节数小于0,则退出循环!
if(hasRead < 0)
break;
rat.write(buff,0,hasRead);
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
//使用finally块来关闭当前线程的输入流、输出流
finally{
try {
if(iStream != null)
iStream.close();
if (rat != null)
rat.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
countDownLatch.countDown();
System.out.println("countDownLatch.getCount():" + countDownLatch.getCount());
System.out.println(this.getId() + "----" + System.currentTimeMillis() + "++++" +
new Date());
}
}