1. 程式人生 > >Java 大文字多執行緒高效讀取

Java 大文字多執行緒高效讀取

本文介紹 Java多執行緒讀取大檔案效能提升的高效方案。

前沿

我們在讀取一個正常檔案的時候,將使用,BufferedReader.read() 的三種方法:

BufferedReader.read()  單位元組,這個效率最低,基本不考了

BufferedReader.read(char[] cbuf)   根據傳入 cbuf 的長度,順序讀取。此方法如果單執行緒的時候,可以考慮,顯然多執行緒不行。

BufferedReader.read(char[] cbuf, int off, int len)  本文中多執行緒高效讀取,需要用到,因為大可以分段讀取呀,有個 off 和 len 夥伴們,就是他了!!!

那麼我們就來實現把。在實習前我仍然需要在強調兩點:

1、InputStream 是個阻塞順序讀取的流物件,也就意味著如果使用多執行緒是,建立一個全域性 InputStream 然後分別傳給不同的子執行緒,且在子執行緒中進行分段讀取,那麼恭喜你你中獎了,你會得到很鬱悶的結果。結果就是子執行緒將不能正常分段獲取!!!

2、BufferedReader.read(char[] cbuf, int off, int len) 中 

cbuf 為緩衝陣列

off 為儲存字元的開始位置

len  一次最多讀入字元個數

        說明:這裡的 off 是個比較鬱悶的欄位,什麼是儲存字元的開始位置,筆者在這裡進行了驗證,當我把 off 以 0傳入的時候正常,以 1 傳入想從第1個字元擷取,也就是執行緒分段擷取的時候,異常就來了。這就麻煩了,如果off 並不是理解上的起始讀取位置,那麼怎麼用多執行緒分段讀取呢???莫慌,且看這裡:reader.skip(this.start); 用這個,夥伴們看到這個你們就成功了。

3、夥伴們請注意看,本文中採用的多執行緒的模式,是假定並不知道文字總長度的情況下進行多執行緒讀取,假定:特殊場景不知道檔案總長度!


接下來,話不多說,上程式碼:

package com.pft.views.webservices.readutil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class ReadUtil {

	private int theadNum = 6 /* 執行緒數 */, timeReadLine = 2048 /* 子執行緒一次迴圈讀取位元組長度 */, timeForTime = 5; /* 子執行緒一次迴圈讀取數 */
	private StringBuffer sbf = new StringBuffer();
	
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		
		ReadUtil rUtil = new ReadUtil();
		rUtil.read(new File("D:\\dslrcv.txt"), 0);
		
		System.out.println("獲取字元總長度:" + rUtil.getSbf().length() + ". 總耗時:" +(System.currentTimeMillis() - start) + "毫秒!");
	}
	
	/**
	 * 假定:特殊場景不知道檔案總長度! 情景下的   遞迴+多執行緒   模式。 可通過File得到總長度,此時可更好的進行子執行緒數的分配和控制。
	 * @param file 檔案
	 * @param start 其實位置
	 */
	public void read(File file, int start){
		List<ReadItem> list = new ArrayList<ReadUtil.ReadItem>();
		
		for(int i = 0; i < theadNum; i++){
			list.add(new ReadItem(file, start + i*timeReadLine*timeForTime));	//建立多個子執行緒
			list.get(list.size()-1).start();
		}
		
		for(int i = 0; i < list.size(); i++){
			try {
				list.get(i).join();
				sbf.append(list.get(i).getSb());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if(list.get(list.size() - 1).getLastNum() == timeReadLine){
			read(file, start + theadNum * timeReadLine * timeForTime);
		}
	}
	
	public StringBuffer getSbf() {
		return sbf;
	}

	/**
	 * 子執行緒
	 * @author James
	 */
	public class ReadItem extends Thread{
		private BufferedReader reader;
		private int start, lastNum;
		private StringBuffer sb;
		
		public ReadItem(File file, int start) {
			try {
				this.reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.start = start;
			this.sb = new StringBuffer();
		}

		@Override
		public void run() {
			char[] buf = new char[timeReadLine];
			try {
				reader.skip(this.start);
				for (int i = 0; i < timeForTime && (lastNum = reader.read(buf)) != -1; i++ ) {
					sb.append(new String(buf,0,lastNum));
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public int getLastNum() {
			return lastNum;
		}

		public StringBuffer getSb() {
			return sb;
		}
	}
}