`
sd6292766
  • 浏览: 102279 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JAVA多线程读写文件范例

阅读更多
    在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址。如果有知情者,烦请帖出地址,我在此文上加入引用或转载。


    本程序是基于这么一种考虑,某系统后台有个将近2G大小的日志文件,你用任何编辑器去打开它,都将会很困难。针对这样的大文件解析处理,解决方案是使用多个线程,分割读取指定的大文件。获取我们所需要的信息。不多说,上代码了,有注释可以帮助理解。


   
package com.thread.multipl.mysolution;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

/**
 * 这个线程用来读取文件,当获取到指定关键字时,在指定的对象加1
 * @author 刘峰管理2
 *
 */
public class ReadThread extends Thread{

	//定义字节数组(取水的竹筒)的长度  
    private final int BUFF_LEN = 256;  
    //定义读取的起始点  
    private long start;  
    //定义读取的结束点  
    private long end; 
    //将读取到的字节输出到raf中  randomAccessFile可以理解为文件流,即文件中提取指定的一部分的包装对象
    private RandomAccessFile raf;  
    //线程中需要指定的关键字
    private String keywords;
    //此线程读到关键字的次数
    private int curCount = 0;
    /**
     * jdk1.5开始加入的类,是个多线程辅助类
     * 用于多线程开始前统一执行操作或者多线程执行完成后调用主线程执行相应操作的类
     */
    private CountDownLatch doneSignal;
    public ReadThread(long start, long end, RandomAccessFile raf,String keywords,CountDownLatch doneSignal){
    	this.start = start;
    	this.end = end;
    	this.raf  = raf;
    	this.keywords = keywords;
    	this.doneSignal = doneSignal;
    }
    
	public void run(){
		try {
			raf.seek(start);
			//本线程负责读取文件的大小  
            long contentLen = end - start;  
            //定义最多需要读取几次就可以完成本线程的读取  
            long times = contentLen / BUFF_LEN+1;  
            System.out.println(this.toString() + " 需要读的次数:"+times);
            byte[] buff = new byte[BUFF_LEN];
            int hasRead = 0;
            String result = null;
            for (int i = 0; i < times; i++) {  
            	//之前SEEK指定了起始位置,这里读入指定字节组长度的内容,read方法返回的是下一个开始读的position
            	hasRead = raf.read(buff);
            	 //如果读取的字节数小于0,则退出循环! (到了字节数组的末尾) 
                if (hasRead < 0) {  
                    break;  
                }  
            	result = new String(buff,"gb2312");
///            	System.out.println(result);
            	int count = this.getCountByKeywords(result, keywords);
            	if(count > 0){
            		this.curCount += count;
            	}
            }
            
    		KeyWordsCount kc = KeyWordsCount.getCountObject();

    		kc.addCount(this.curCount);
    		
    		doneSignal.countDown();//current thread finished! noted by latch object!
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public long getStart() {
		return start;
	}

	public void setStart(long start) {
		this.start = start;
	}

	public long getEnd() {
		return end;
	}

	public void setEnd(long end) {
		this.end = end;
	}

	public RandomAccessFile getRaf() {
		return raf;
	}

	public void setRaf(RandomAccessFile raf) {
		this.raf = raf;
	}
	
	public int getCountByKeywords(String statement,String key){
		return statement.split(key).length-1;
	}

	public int getCurCount() {
		return curCount;
	}

	public void setCurCount(int curCount) {
		this.curCount = curCount;
	}

	public CountDownLatch getDoneSignal() {
		return doneSignal;
	}

	public void setDoneSignal(CountDownLatch doneSignal) {
		this.doneSignal = doneSignal;
	}
}


package com.thread.multipl.mysolution;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

public class MultiReadTest {

	/**
	 * 多线程读取文件测试
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final int DOWN_THREAD_NUM = 10;//起10个线程去读取指定文件
		final String OUT_FILE_NAME = "d:\\倚天屠龙记.txt";
		final String keywords = "无忌";
		 //jdk1.5线程辅助类,让主线程等待所有子线程执行完毕后使用的类,
        //另外一个解决方案:自己写定时器,个人建议用这个类
        CountDownLatch doneSignal = new CountDownLatch(DOWN_THREAD_NUM);
		RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM];
		try{
			long length = new File(OUT_FILE_NAME).length();
			System.out.println("文件总长度:"+length+"字节");
			//每线程应该读取的字节数  
            long numPerThred = length / DOWN_THREAD_NUM;  
            System.out.println("每个线程读取的字节数:"+numPerThred+"字节");
          //整个文件整除后剩下的余数  
            long left = length % DOWN_THREAD_NUM;
            for (int i = 0; i < DOWN_THREAD_NUM; i++) {  
                //为每个线程打开一个输入流、一个RandomAccessFile对象,  
            	
                //让每个线程分别负责读取文件的不同部分
            	outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");  
                if (i != 0) {  
//  
//                    isArr[i] = new FileInputStream("d:/勇敢的心.rmvb");  
                    //以指定输出文件创建多个RandomAccessFile对象  
                    
                }  
                if (i == DOWN_THREAD_NUM - 1) {  
//                    //最后一个线程读取指定numPerThred+left个字节  
//               	System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred+ left)+"的位置");
                    new ReadThread(i * numPerThred, (i + 1) * numPerThred  
                            + left, outArr[i],keywords,doneSignal).start();  
                } else {  
                    //每个线程负责读取一定的numPerThred个字节  
//                	System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred)+"的位置");
                    new ReadThread(i * numPerThred, (i + 1) * numPerThred,  
                            outArr[i],keywords,doneSignal).start();  
                }  
            }
		}catch(Exception e){
			e.printStackTrace();
		}
//		finally{
//			
//		}
		//确认所有线程任务完成,开始执行主线程的操作
		try {
			doneSignal.await();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//这里需要做个判断,所有做read工作线程全部执行完。
		KeyWordsCount k = KeyWordsCount.getCountObject();
//		Map<String,Integer> resultMap = k.getMap();
		System.out.println("指定关键字出现的次数:"+k.getCount());
	}

}


package com.thread.multipl.mysolution;


/**
 * 统计关键字的对象
 * @author 刘峰管理2
 *
 */

public class KeyWordsCount {
	
	private static KeyWordsCount kc;
	
	private int count = 0;
	private KeyWordsCount(){
		
	}
	
	public static synchronized KeyWordsCount getCountObject(){
		if(kc == null){
			kc = new KeyWordsCount();
		}
		return kc;
	}

	public synchronized void  addCount(int count){
		System.out.println("增加次数:"+count);
		this.count += count;
	}
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}
	
}


运行结果如下:
引用
文件总长度:2012606字节
每个线程读取的字节数:201260字节
Thread[Thread-0,5,main] 需要读的次数:787
Thread[Thread-1,5,main] 需要读的次数:787
Thread[Thread-2,5,main] 需要读的次数:787
Thread[Thread-3,5,main] 需要读的次数:787
Thread[Thread-4,5,main] 需要读的次数:787
Thread[Thread-5,5,main] 需要读的次数:787
Thread[Thread-6,5,main] 需要读的次数:787
Thread[Thread-7,5,main] 需要读的次数:787
Thread[Thread-8,5,main] 需要读的次数:787
Thread[Thread-9,5,main] 需要读的次数:787
增加次数:0
增加次数:146
增加次数:432
增加次数:539
增加次数:587
增加次数:717
增加次数:631
增加次数:467
增加次数:665
增加次数:538
指定关键字出现的次数:4722


我用10个线程去解析金庸大师写的《倚天屠龙记》,“无忌”这个词在这部小说中一共出现了4722次。实在找不到再大一些的文件了。倚天屠龙记.txt的大小4M出头。

关于CountDownLatch类的作用说明:
    在API文档中,已经说明是一个辅助类。用于控制主线程与子线程之间切换的一个工具类。用法网上去搜下。ITEYE里也有人讨论过。我在这里使用它解决这样的问题:在确保10个线程都完成文件的解析工作后,系统调用主线程做剩下该做的事情,即:输出“出现的次数”。不确保这点的话,会导致执行完第4个线程,后面的线程还没开始,系统已经做最后一步输出统计结果,这样就达不到我们要的效果。这里解决方案有另一个简单的,自己写个计数器,从10记到1,10个线程嘛。这个看个人喜好吧。
分享到:
评论
2 楼 karistino 2015-11-30  
设定的进程数目不同时统计的关键字个数不一样
1 楼 zhouwei849712382 2013-03-16  
你这个我测试了,不行的

相关推荐

    Java多线程下载器范例

    综上所述,"Java多线程下载器范例"涉及了Java多线程编程、文件I/O操作、线程同步和通信、下载策略等多个核心概念。通过理解和实践这些知识点,开发者可以构建出高效、稳定的文件下载工具。在实际项目中,这样的下载...

    JAVAJAVA多线程教学演示系统论文

    总的来说,《JAVA多线程教学演示系统》这篇论文不仅是对JAVA多线程技术的理论探讨,更是一个实践与教学相结合的优秀范例,对于提升学生的多线程编程能力具有很高的参考价值。VB图书管理系统论文范文虽不在本文讨论...

    Java项目设计与开发范例

    8. **多线程编程**:Java提供了强大的多线程支持,理解线程同步、并发控制、死锁避免等概念,对于高并发应用的开发非常重要。 9. **网络编程**:Java的Socket编程允许创建基于TCP/IP的网络应用,理解网络通信的基本...

    JAVA编程通用范例

    4. **多线程**:Java提供了内置的多线程支持,如Thread类和Runnable接口。通用范例可能会包含线程同步、锁机制(如synchronized关键字、ReentrantLock等)、并发工具类(如ExecutorService、CountDownLatch、...

    java开发范例大全

    6. **多线程**:Java支持并发编程,范例可能包含线程的创建、同步、线程池的使用等。理解如何在多线程环境下协调任务执行,是构建高性能应用程序的关键。 7. **反射机制**:Java的反射机制允许在运行时动态访问类的...

    《java完全自学手册》范例程序代码册.rar

    6. **多线程**:Java支持多线程编程,通过Thread类或Runnable接口可以创建并管理线程。实例代码可能包含同步机制,如synchronized关键字、wait()和notify()方法,用于解决并发问题。 7. **GUI编程**:Java的Swing和...

    Java通用范例开发金典

    6. **多线程**:Java内置了对多线程的支持,包括Thread类和Runnable接口,以及synchronized关键字、wait()、notify()等同步机制。理解并发编程原理,能有效提升程序的并行性能。 7. **网络编程**:Java提供了Socket...

    JAVA语言与其程序设计范例.rar

    这些范例通常包括了基础语法、类与对象、接口、异常处理、集合框架、多线程、输入/输出流、网络编程、数据库连接(JDBC)等核心概念。通过这些范例,学习者可以更直观地理解和掌握Java编程的各种技术。 1. **基础...

    JAVA项目开发实践的范例

    5. **多线程编程**:Java提供了丰富的多线程支持,范例可能会演示如何创建和管理线程,以及如何使用同步机制避免并发问题。这对构建高并发、高性能的应用至关重要。 6. **设计模式**:面向对象的设计模式如单例、...

    《Java通用范例开发金典》

    在Java编程中,通用范例通常包括基础语法、面向对象编程、异常处理、集合框架、多线程、网络编程、I/O流、数据库操作、GUI设计、反射、注解等多个方面。下面将对这些知识点进行详细的阐述: 1. **基础语法**:Java...

    [JAVA编程模式与范例].zip

    【JAVA编程模式与范例】这个压缩包文件主要聚焦于Java编程中的设计模式和实例应用。设计模式是软件工程中经过实践验证的、在特定场景下解决常见问题的有效方法,而Java作为广泛应用的面向对象编程语言,其设计模式的...

    Java通用范例开发金典源代码

    4. **多线程** - 线程的创建与管理:通过实现Runnable接口或继承Thread类创建线程。 - 同步机制:synchronized关键字的使用,以及wait()、notify()和notifyAll()方法的理解。 - 线程池:ExecutorService和...

    java 范例大全源代码

    多线程编程也是Java的一大特色。通过实现Runnable接口或继承Thread类,可以创建并运行多个线程。在并发编程中,锁、同步机制、并发容器(如ConcurrentHashMap)等工具用于保证线程安全。源代码会展示如何编写并发...

    JAVA语言与其程序设计范例

    最后,Java还提供了丰富的标准库,如Math类用于数学运算,Date和Calendar类处理日期和时间,Thread类支持多线程编程,等等。熟练掌握这些库将极大地提升开发效率。 总的来说,“JAVA语言与其程序设计范例”涵盖了从...

    java项目设计与开发范例源码

    6. **多线程**:Java支持多线程编程,源码可能会包含并发执行任务的示例,学习如何同步、互斥、线程通信等。 7. **网络编程**:部分项目可能涉及到Socket编程,用于实现客户端和服务器之间的通信。 8. **GUI编程**...

    JAVA语言与其程序设计范例.rar_Java 程序设计_java程序_java程序设计_程序设计

    Java内置了对多线程的支持,通过Thread类和Runnable接口可以实现并发执行。理解线程的生命周期、同步机制(如synchronized关键字、wait()和notify()方法)以及线程池,有助于优化程序性能。 7. **网络编程** Java...

    java2范例入门与提高(初学JAVA者)

    IO流用于读写文件和网络通信,多线程则让程序可以同时执行多个任务。网络编程则涉及到Socket通信,是构建分布式系统的基础。 在实践中提升是学习Java的重要环节,读者应动手编写代码,跟随书中的例子进行实践,逐步...

    《java范例大全》源代码

    这份源代码不仅覆盖了基础语法,还包括了面向对象编程、异常处理、集合框架、多线程、网络编程、I/O流、数据库操作等Java核心领域的实例。以下将对这些知识点进行详细阐述。 1. **基础语法**:Java的基础语法是学习...

Global site tag (gtag.js) - Google Analytics