1. 程式人生 > >Java多執行緒讀取大檔案

Java多執行緒讀取大檔案

前言

  今天是五一假期第一天,按理應該是快樂玩耍的日子,但是作為一個北漂到京師的開發人員,實在難想出去那玩耍。好玩的地方比較遠,近處又感覺沒意思。於是乎,閒著寫篇文章,總結下昨天寫的程式吧。

  昨天下午朋友跟我聊起,他說有個需求,需要把上G的txt檔案讀取寫入到資料庫。用普通的io結果自然是OOM了,所以果斷用NIO技術。為了提高速度,自然還得用上多執行緒技術。

  接下來就介紹一下實現思路以及相關的知識點。

內容

     一、對檔案分割槽

        為了充分利用多執行緒讀取,就需要把檔案劃分成多個區域,供每個執行緒讀取。那麼就需要有一個演算法來計算出每個執行緒讀取的開始位置和結束位置。那麼首先根據配置的執行緒數和檔案的總長度計,算出每個執行緒平均分配的讀取長度。但是有一點,由於檔案是純文字檔案,必須按行來處理,如果分割點在某一行中間,那麼這一行資料就會被分成兩部分,分別由兩個執行緒同時處理,這種情況是不能出現的。所以各個區域的結束點上的字元必須是換行符。第一個區域的開始位置是0,結束位置首先設為(檔案長度/執行緒數),如果結束點位置不是換行符,就只能加1,直到是換行符位置。第一個區域的結束位置有了,自然我們就能求出第二個區域的開始位置了,同理根據上邊演算法求出第二個區域的結束位置,然後依次類推第三個、第四個......

        上邊的演算法中,第一個區域的結束位置定了,才能有第二個區域的開始位置,第二個區域的結束位置定了,才能有第三個區域的開始位置,依次這麼下去。照這種規律,自然地想到的是用遞迴來解決。(詳情看原始碼

    二、記憶體檔案對映

      簡單說一下記憶體檔案對映:

記憶體檔案對映,簡單地說就是將檔案對映到記憶體的某個地址上。 要理解記憶體檔案對映,首先得明白普通方式讀取檔案的流程: 首先記憶體空間分為核心空間和使用者空間,在應用程式讀取檔案時,底層會發起系統呼叫,由系統呼叫將資料先讀入到核心空間,然後再將資料拷貝到應用程式的使用者空間供應用程式使用。這個過程多了一個從核心空間到使用者空間拷貝的過程。
如果使用記憶體檔案對映,檔案會被對映到實體記憶體的某個地址上(不是資料載入到記憶體),此時應用程式讀取檔案的地址就是一個記憶體地址,而這個記憶體地址會被對映到了前面說到的實體記憶體的地址上。應用程式發起讀之後,如果資料沒有載入,系統呼叫就會負責把資料從檔案載入到這塊實體地址。應用程式便可以讀取到檔案的資料。省去了資料從核心空間到使用者空間的拷貝過程。所以速度上也會有所提高。

      在我的讀取大檔案的實現中,就是用了Java的記憶體對映API,這樣我們就可以在要讀取某個地址時再將內容載入到記憶體。不需要一下子全部將內容載入進來。

總結

  以上就是我主要用到的思路和一些技術點吧。可能存在某些表達不清楚的地方,望大神勿噴^_^

  具體實現請參考程式碼吧,這裡是程式碼的地址(Java讀取大檔案