`
ForgetLove
  • 浏览: 24539 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

    博客分类:
  • java
 
阅读更多


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

 
  • 大小: 31.3 KB
分享到:
评论

相关推荐

    QT多线程编程、主线程与子线程交互数据

    本文将深入探讨QT多线程编程的核心概念,主线程与子线程之间的数据交互以及如何在VS2017中进行实际应用。 首先,理解QT中的线程模型至关重要。在QT中,主线程通常负责用户界面的更新和事件处理,而子线程则可以执行...

    Java多线程--让主线程等待所有子线程执行完毕

    然而,在多线程环境下,如果直接在主线程中记录开始和结束时间,由于子线程是并发执行的,主线程不会等待子线程完成就会继续执行,导致记录的总用时可能并不准确。 **2. 使用`join()`方法的局限性** 尝试在每个子...

    Python多线程:主线程等待所有子线程结束代码

    本篇文章将深入探讨如何在Python中实现多线程,并让主线程等待所有子线程结束。 首先,我们需要了解Python中的`threading`模块,它是Python标准库中用于处理多线程的模块。在示例代码中,我们创建了两个函数`a()`和...

    子线程更新主线程数据

    在多线程编程中,"子线程更新主线程数据"是一个常见的需求,尤其是在UI界面交互和后台处理相结合的应用中。主线程通常负责用户界面的显示与交互,而子线程则用于执行耗时的任务,避免阻塞主线程,提供良好的用户体验...

    C#子线程执行完后通知主线程的方法

    在C#编程中,多线程是常见的并发执行方式,其中主线程通常负责应用程序的主逻辑,而子线程则可以执行一些独立的任务。当子线程完成其工作后,有时需要通知主线程以便进行下一步操作。本文将详细介绍如何在C#中实现...

    Java主线程等待子线程执行完毕

    Java 中的多线程编程是非常重要的一部分,特别是在需要并发执行多个任务的情况下。然而,在某些情况下,我们需要等待所有子线程执行完毕后再继续执行主线程的剩余动作。这时,我们可以使用 Java 提供的 ...

    java 子线程通过观察者模式通知主线程

    在多线程环境下,观察者模式可以被巧妙地应用于子线程通知主线程的情况。 观察者模式的核心思想是定义一个一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在Java中,`...

    Java多线程–让主线程等待所有子线程执行完毕

    线程启动后,它们会并发运行,而主线程也会继续执行,导致主线程在for循环结束后立即计算总耗时,此时所有子线程可能并未全部完成。 要解决“让主线程等待所有子线程执行完毕”的问题,可以采用以下策略: 1. 使用...

    Java简单实现“主线程等待所有子线程完成再继续”

    总的来说,Java提供了丰富的多线程同步机制,可以根据实际需求选择合适的方法来实现“主线程等待所有子线程完成再继续”的功能。在并发编程中,理解并灵活运用这些工具对于提高程序效率和避免死锁等问题至关重要。

    Java多线程--让主线程等待所有子线程执行完毕在执行

    在Java多线程编程中,有时我们需要确保主线程在所有子线程完成执行后再继续执行。这在处理大量并发任务,比如数据导入、并行计算等场景中是常见的需求。以下是如何实现这一功能的详细解释。 首先,让我们理解为什么...

    Java多线程--等待所有子线程执行完的五种方法.docx

    在Java多线程编程中,有时我们需要确保所有子线程执行完毕后再进行后续操作,例如在并发测试、数据聚合或资源清理等场景。本篇文章将详细介绍五种在Java中等待所有子线程执行完的方法。 ### 方法一:使用`sleep`...

    多线程线程变量赋值

    在这个例子中,主线程设置了`ThreadLocal`变量的值,但每个子线程在自己的上下文中运行时,它们看到的`ThreadLocal`变量值是独立的。因此,`thread1`和`thread2`可能会打印出不同的值,因为它们拥有各自的副本。 ...

    子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。

    标题中的内容涉及到多线程编程,具体是一种交替执行的任务模式,即子线程循环10次,然后主线程循环100次,这样的交替过程重复50次。这是一个典型的线程交互场景,常用于实现并发任务,比如在GUI应用中更新界面或者在...

    PB多线程实现

    // 主线程等待子线程结束 } } ``` 总的来说,PB系列(尤其是PB12.5和PB.NET)提供了多种多线程实现方式,适应了不同开发需求。理解并掌握这些技术,能帮助开发者构建更加高效、响应迅速的PB应用程序。

    python爬虫-08-主线程会等待子线程执行结束再结束.ev4.rar

    在Python中,多线程是一种并发执行的方式,可以提高程序的运行效率。`threading`模块提供了创建和管理线程的功能。在爬虫项目中,多线程常用于并行下载网页或处理大量请求,以提高爬取速度。 主线程是程序启动时...

    多线程并发代码的IntelliJ IDEA中调试方法.docx

    ### 多线程并发代码的IntelliJ IDEA中调试方法 #### 一、代码解析 在探讨如何使用IntelliJ IDEA进行多线程代码调试之前,先了解代码本身的功能。 **1.1 代码功能** 代码的主要目的是计算两个非常大的数字的阶乘...

    MulThread.rar_多线程 进度条_子线程界面_进度条 多线程

    在多线程编程中,通常会在主线程中更新进度条,以反映后台任务的完成情况。进度条的更新需要与工作线程的执行进度同步,确保用户能实时看到任务状态。 3. **子线程界面**:在描述中提到,一个线程控制进度条,这...

    多线程执行完后主程序再执行(包括需要子线程返回结果)

    在上述示例中,`join()`方法确保了主线程在子线程执行完毕后才继续运行,防止了数据竞争和资源泄漏。 其次,关于子线程返回结果到主线程的问题,我们可以利用共享变量、线程间通信或者回调函数来实现。在Java中,...

    线程中创建子线程

    总结来说,"线程中创建子线程"是多线程编程的一个重要方面,它涉及线程的创建、管理和同步,以及如何利用这一机制提升程序的并发性和性能。在实际编程中,理解并掌握这些概念和技术,对于编写高效、可靠的多线程程序...

    通过窗口传递让主线程触发FIRE事件(子线程不能触发)

    总结起来,通过窗口传递来让主线程触发FIRE事件是一种常见的解决策略,它遵循了多线程编程的最佳实践,确保了线程安全和UI一致性。理解这些概念和技术对于开发高效且稳定的多线程Windows应用程序至关重要。

Global site tag (gtag.js) - Google Analytics