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

来源:互联网 发布:淘宝购物券在哪里设置 编辑:程序博客网 时间:2024/06/14 06:33

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