2015-12-08 2 views
1

Я пытаюсь написать код на Java, чтобы прочитать файл по пару потоков и подсчитать слова в них. Каждый поток должен читать разные строки. Он хорошо подсчитывает слова (когда я пропускаю 1 поток), но мои потоки читают одну и ту же строку и одновременно увеличивают счетчик строк. Я был уверен, что ключевое слово synchronized в методе чтения исправит его, но это не так. Что мне делать, чтобы исправить это?Чтение многопоточного файлов

import java.io.BufferedReader; 
import java.io.FileReader; 
import java.io.IOException; 
import java.util.*; 
import java.util.concurrent.atomic.AtomicInteger; 


public class WordCounterr implements Runnable { 
    private static Hashtable<String, Integer> ht = new Hashtable<String, Integer>(); 
    private int lineCounter; 
    private String path; 
    private int tNumber; 
    //private final AtomicInteger whichLine = new AtomicInteger(); 
    private static int whichLine; 
    private static boolean flag; 

    public WordCounterr(String path,int num){ 
     lineCounter = 0; 
     //whichLine = 0; 
     flag= false; 
     this.path=path; 
     tNumber = num; 
    } 

    public void countWords(String s) throws IOException{ 
     char[] c = s.toCharArray(); 
     String str=""; 
     char ch;   
     for(int k=0;k<c.length;k++){       

      ch=c[k];      
      if((ch>40 && ch<91) ||(ch>96 && ch<123)){  
       if(ch>40 && ch<91) 
        ch+=32;    
       str+=ch; 
      }   
      else if(ch==32 ||k==c.length-1){ 
       if(str.length()>1){ //sprawdzamy czy funkcja znalazla juz 
        if(ht.containsKey(str))  //takie slowo    
         ht.put(str,ht.get(str)+1); //znalazla - powiekszamy wartosc przy kluczu 
        else 
         ht.put(str,1); //nie znalazla - dodajemy slowo do Hashtable    

       } 
       str=""; 
      } 
     } 
    } 

    public synchronized void read(String path) throws IOException{ 
     BufferedReader buf=new BufferedReader(new FileReader(path)); 

     String linia ; 
     for(int i=0;i<whichLine;i++){ 
      linia=buf.readLine(); 
     } 

     if((linia=buf.readLine())!=null){ 
      System.out.println(linia); 
      countWords(linia); 
      lineCounter++; 
      System.out.println("watek nr:"+tNumber+"ktora linia:"+whichLine);    
      whichLine++; 
      /*try{ 
        Thread.sleep(100); 

       }catch(InterruptedException el){ 
        System.out.println(el.toString()); 
       }*/ 
     } else 
      setFlag(true); 

     buf.close(); //pamietamy o zamknieciu pliku 

    } 

    public synchronized void print(){ 
     if(getFlag()){ 
      setFlag(false);   
      System.out.println(ht); 
     } 
     System.out.println("watek nr: "+tNumber+", przeanalizowano "+ lineCounter+ "linii tekstu"); 
    } 

    public void setFlag(boolean val){ 
     flag=val; 
    } 

    public boolean getFlag(){ 
     return flag; 
    } 

    @Override 
    public void run() { 
     try{  

      while(getFlag()==false) { 
       read(path); 
       Thread.yield(); //let other thread read 
       try { 
        Thread.sleep(100); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     }catch(IOException ex){ 
      System.out.println(ex.toString()); 
     }//catch(InterruptedException el){ 
     // System.out.println(el.toString()); 
     //}  
     print(); 
    } 

    public static void main(String[] args) throws IOException, InterruptedException{ 
     String path = args[0]; 
     int tNum = Integer.parseInt(args[1]); 

     Thread[] thread = new Thread[tNum]; // tablica w?tków 
     for (int i = 0; i < tNum; i++){ 
      thread[i] =new Thread(new WordCounterr(path,i)); 
     } 

     for (int i = 0; i < tNum; i++) 
      thread[i].start(); 
     } 
} 

ответ

1

синхронизированная модификатор определяется так: it is not possible for two invocations of synchronized methods on the same object to interleave.

Вы вызываете метод read в каждом из вашего Threads.

Однако вы не вызывая тот же методread, потому что вы передаете новые экземпляры WordCounterr к каждому новому Thread. Это означает, что вы вызываете метод на разные объекты, которые не будут выполняться синхронизированным модификатором.

Чтобы исправить эту попытку:

WordCounterr reader = new WordCounterr(path,0); //I changed i to 0 because it can't differentiate between threads with a simple int. This is because each Thread now references the same object. 
Thread[] thread = new Thread[tNum]; // tablica w?tków 
for (int i = 0; i < tNum; i++){ 
    thread[i] =new Thread(reader); 
} 

Вместо:

Thread[] thread = new Thread[tNum]; // tablica w?tków 
for (int i = 0; i < tNum; i++){ 
    thread[i] =new Thread(new WordCounterr(path,i)); 
} 

Я надеюсь, что это помогает :)

+0

Да, это помогает. Но теперь у меня есть 1 экземпляр объекта WordCounterr и не вижу, сколько строк анализируется каждый поток :(Любая идея, как синхронизировать 2 или более экземпляров класса WordCounterr? – stackwack

+0

@stackwack сделать это, что я бы рекомендовал посмотреть на ответ gauee , Который синхронизирует читателя, а не методы. – StephenButtolph

1

Я предполагаю, что это все еще будет неэффективное чтение содержимого файла. Попробуйте изменить точку синхронизации. Он должен быть помещен в метод чтения. Этот метод читает содержимое всего файла. Скорее, попробуйте синхронизировать только чтение следующей строки этого файла. Вы можете добиться этого, поставив на каждый экземпляр WordCounterr один и тот же экземпляр файла-читателя и синхронизировав только процесс перемещения указателя на следующую строку, читающую содержимое этой строки. Подсчет слов в строке может выполняться без синхронизации, и только синхронизация HashTable должна выполняться только с помощью обновления. Параметр чтения содержимого файла может быть синхронизирован следующим образом:

static class Reader implements Runnable { 
    int lineReaded = 0; 
    final Scanner scanner; 

    Reader(Scanner scanner) { 
     this.scanner = scanner; 
    } 

    public void run() { 
     boolean hasNext = true; 
     while (hasNext) { 
      hasNext = false; 
      synchronized (scanner) { 
       if (scanner.hasNext()) { 
        hasNext = true; 
        String line = scanner.nextLine(); 
        ++lineReaded; 
       } 
      } 
      try { 
       Thread.sleep((long) (Math.random() * 100)); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
Смежные вопросы