2017-06-25 113 views
-2

我已經閱讀了關於使用多線程讀取文件的一些答案,並且還發現它的效率非常差,但仍然爲了學習,我正嘗試使用多線程讀取文件,即針對大文件很少的記錄應該由另一個線程讀取。在java中使用多線程讀取txt文件

import java.io.File; 
import java.io.FileNotFoundException; 
import java.util.ArrayList; 
import java.util.Scanner; 

public class QueueThread implements Runnable { 

    int count=0; 
    private int start; 
    private int end; 

    public QueueThread(int start,int end) { 
     this.start=start; 
     this.end=end; 


    } 

    public void run() { 

     for(int i=start;i<end;i++) {   

     try { 
      Scanner read = new Scanner (new File("userinfo.txt")); 
      read.useDelimiter(",|\n"); 
      String mobile,recharge; 

      while(read.hasNext()) 
      {     
       mobile = read.next(); 
       recharge =read.next(); 

       ArrayList<String> words = new ArrayList<String>(); 
       words.add(mobile+recharge); 

       count++; 

       System.out.println("mobile no.:"+ mobile); 
       System.out.println("recharge amount:"+ recharge); 
       System.out.println("count:"+ count); 
      } 

      read.close(); 

     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     } 
    } 
} 

Control.java:

public class Control { 
    public static void main(String args[]) throws InterruptedException 
    { 
     QueueThread r1=new QueueThread(0,15); 
     QueueThread r2=new QueueThread(15,30); 
      Thread t1 =new Thread(r1); 
      Thread t2 =new Thread(r2); 

      t1.start(); 
      t2.start(); 

      t1.join(); 
      t2.join(); 


    } 
} 

我在這裏讀文件userinfo.txt用一些隨機的10位無。和一些號碼。每個線程讀取整個文件,而不是隻讀取一個線程中的前15個條目和另一個線程中的其他14個條目,我相信這並不會破壞我並行讀取文件的座右銘。 我也試圖將提取的數據存儲在ArrayList中以對其執行進一步的操作。

userinfo.txt

9844794101,43 
9844749102,54 
9844741903,55 
9844741094,33 
9844741095,87 
9844741068,32 
9844974107,53 
8848897101,343 
8848891702,345 
8848891063,34 
8848849104,64 

我真的很需要一些出路在不同的線程同時讀取該文件

電流輸出上

mobile no.:9844794101 
recharge amount:43 
mobile no.:9844794101 
count:1 
recharge amount:43 
count:1 
mobile no.:9844749102 
recharge amount:54 
mobile no.:9844749102 
recharge amount:54 
count:2 
count:2 

等等

+2

我不知道爲什麼最近有很多關於多線程閱讀的問題(請看右邊的相關問題)。因爲I/O硬件(磁盤,數據總線,...)是瓶頸而不是CPU,所以通常沒有多少好處。 – Henry

+1

爲了學習*什麼*?您可以在單個線程中每秒讀取數百萬行。通過將問題分成線程,你甚至希望獲得什麼,甚至在智力上? – EJP

+0

如果你想了解多線程,閱讀一個相對較小的文件不是正確的問題。 –

回答

1

如果是爲了學習,那麼只需在兩個線程中使用一個Scanner對象。既然你需要閱讀一對相鄰的單詞然後加入它們,你就必須考慮一些解決方案,讓你的兩個線程工作。

最簡單的方法是允許每個線程使用'synchronized(scannerObject){...}來讀取幾個單詞。當然,性能會比單線程解決方案差。其他解決方案可避免同步,例如如果您使用AtomicInteger作爲計數器並將這些單詞存儲在從計數器到下一個單詞的ConcurrentSkipListMap中。

我認爲經典的方法是在文件的中間知道一個精確的點,從中你可以閱讀一個新詞。然後你的第一個線程會從頭到尾讀取一個文件,第二個線程可以從「中間」位置讀到最後。見例如Make BufferedReader start from the middle of a .txt file rather than the beginning?

0

而不是

Scanner read = new Scanner (new File("userinfo.txt")); 

你需要使用像

InputStream inputStream = new BufferedInputStream(new FileInputStream(new File("userinfo.txt")))); 
inputStream.skip(<number of bytes to start of first desired record>); 
Scanner read = new Scanner(inputStream); 
// then make sure you only read as many records as you need 

搜索更多有關InputStream S和Reader秒。

問題是,鑑於你的記錄格式,有沒有辦法讓正確的參數skip沒有閱讀文件的前一部分(雖然你只需要尋找新行,而不是,|)。您可以製作startend字節數而不是記錄數,但是您需要知道您可能會落在記錄的中間,並且要小心。另外,如果你想要最後的ArrayList按順序,那麼第二個線程將不得不等待,直到第一個線程完成插入爲止。如果您不這樣做,請務必同步對其的訪問或使用https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html