【OS大作业】用多线程统计txt文件中字符个数(Java实现)

该博客介绍了使用Java实现多线程统计txt文件中字符个数的大作业。通过对比单线程和多线程版本的代码,分析线程数量与查找时间的关系。实验结果显示,线程数在4个以下时性能提升明显,超过4个后性能提升放缓,到8个线程时达到最优,之后增加线程可能导致性能下降。
摘要由CSDN通过智能技术生成

问题描述

给定一个txt文件,利用不同个数的线程查找文件中某字符的个数,探究线程个数与查找时间的关系。

本作业代码使用JAVA实现,版本为10.0.2,使用的IDE为Eclipse4.9.0. 结果测试所用的txt文件内容为英文,编码格式为UTF-8。

源代码

第一版代码:(仅支持单线程、按行读取、可以读取字符串/字符,速度快)

package searchtxt;	//包名称

import java.io.BufferedReader;	//缓冲字符输入流
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/* *
 * 读取一txt文档,每次读取一行,用BufferedReader(FileReader fr)
 * */

public class demo {
	static int totalCount;		//待查找关键字的个数
	static String key = "a";	//带查找关键字字符串
	public static void main(String[] args) throws IOException {
		Thread1 mTh1=new Thread1(); 	//创建一个线程
		mTh1.setTotalCount(0);			//传参,关键字个数初始化为0
		mTh1.setKey(key);				//传入要查找的关键字
		mTh1.start();  					//开启线程,运行run方法
		totalCount=mTh1.getTotalCount();	//获取该线程查找结果
	}

	
}

class Thread1 extends Thread{		//继承自Thread类
	private int totalCount; 		//关键字个数
	private String key;				//关键字字符串
    @SuppressWarnings("resource")
	public void run() { 
    		File f = new File("src/OneHundredYearsofSolitude.txt");	//待查找文件路径
    		FileReader fr;		//该类按字符读取流中数据
    		String str;
		try {
			long startTime=System.currentTimeMillis();   //获取开始时间
			fr = new FileReader(f);		
			BufferedReader br = new BufferedReader(fr);
			//开始读取文件直到末尾
	    		while ((str = br.readLine()) != null) {
	   	 	//将每次读取的数据放入str字符串中,在其中查找关键字key的个数加入totalcount
				setTotalCount(getTotalCount() + countKey(str, key));
	   	 	}
	    		long endTime=System.currentTimeMillis(); //获取结束时间
			
	    		//输出结果
			System.out.println("文章中一共出现了:" + key + ":" + totalCount + "次");
			System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
		} catch (IOException e1) {
			e1.printStackTrace();
		}
}  
    
    //该方法从str中查找key,返回个数
    public static int countKey(String str, String key){
		int index = 0;
		int count = 0;
		while ((index = str.indexOf(key, index)) != -1) {
			index += key.length();
			count++;
		}
		return count;
	}
	public int getTotalCount() {
		return totalCount;
	}
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
	public void setKey(String key) {
		this.key = key;
	}
}  

第二版代码:(可自行选择总线程个数,将文件分块让各个线程按字符查找)

1、MultiReadTest.java(主程序)

package searchtxt;

import java.io.File;
import java.io.RandomAccessFile; 	//用于读写文件
import java.util.concurrent.CountDownLatch; 	//CountDownLatch类,用于线程同步
  
/* *
  * 用n个线程读取txt文件,当获取到指定关键字时,在指定的对象加1 
 * */  

public class MultiReadTest {  
    @SuppressWarnings("resource")
	public static void main(String[] args) {  
    	//开始时间设为0
    	long startTime=0;
    	//结束时间设为0
    	long endTime=0;
    	
    	/*
    	//可手动输入线程数目,调试时注释掉
		Scanner input= new Scanner(System.in);   //为Scanner实例化对象input
        int n=input.nextInt();                   //扫描控制台输入
        final int DOWN_THREAD_NUM = n; 
    	*/
    	//
    	//指定线程数目
    	//final成员变量必须在声明的时候初始化或在构造方法中初始化,不能再次赋值。
        final int DOWN_THREAD_NUM = 8; 
        //
        
        //要读取的txt文件路径
        final String OUT_FILE_NAME = "src/8MB.txt";
        //要查找的关键字
        final String keywords = "a";  
        
        //CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。
        //具体使用方法为:
        //CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。 
        //当我们调用一次CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await会阻塞当前线程,直到N变成零。
        //在这里,我们设置CountDownLatch的值为DOWN_THREAD_NUM
        CountDownLatch doneSignal = new CountDownLatch(DOWN_THREAD_NUM);  
        
        //RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,可以读取文件内容,也可以向文件输出数据
        //与普通的输入/输出流不同的是,RandomAccessFile支持跳到文件任意位置读写数据
        //RandomAccessFile对象包含一个记录指针,用以标识当前读写处的位置
        //当程序创建一个新的RandomAccessFile对象时,该对象的文件记录指针对于文件头(也就是0处)
        //当读写n个字节后,文件记录指针将会向后移动n个字节
        //除此之外,RandomAccessFile可以自由移动该记录指针
        RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM];  
        
        try{  
        	//此方法用于获取文件长度,最大只能获取2g的文件大小,因为返回值类型为long
            long length = new File(OUT_FILE_NAME).length();  
            //输出文件长度
            System.out.println("文件总长度:"+length+"字节,即"+length/1024/1024+"MB");  
            
            //计算每个线程应该读取的字节数    
            long numPerThred = length / DOWN_THREAD_NUM;
            System.out.println("共有"+DOWN_THREAD_NUM+"个线程,每个线程读取的字节数:"+numPerThred+"字节");  
            
            //计算整个文件整除后剩下的余数    
            long left = length % DOWN_THREAD_NUM;
            
            //获取开始时间
            startTime=System.currentTimeMillis();
            
            //为每个线程打开一个输入流、一个RandomAccessFile对象
            //让每个线程分别负责读取文件的不同部分
            for (int i = 0; i < DOWN_THREAD_NUM; i++) {  
            	//rw:以读取、写入方式打开指定文件
                outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");   
                
                //最后一个线程读取指定numPerThred+left个字节    
                if (i == DOWN_THREAD_NUM - 1) {    
                	//输出其要读的字节范围(测试时应把这句注释掉,因为会影响运行时间的测定)
                	//System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThre
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值