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; } } }