多线程以及主线程等待并发子线程运行

首先,用到的线程类有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());
	}
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值