2013-08-19 2 views
0

Я новичок в многопоточности и синхронизации в java. Я пытаюсь выполнить задачу, в которой мне дано 5 файлов, каждый файл будет считаться одним конкретным потоком. Каждый поток должен читать одну строку из файла, а затем переводить в следующий поток и так далее. Когда все 5 потоков прочитают первую строку, затем снова начните с строки № 1. 2 файла 1 и так далее.Запуск потоков в круговой форме robin в java

Thread ReadThread1 = new Thread(new ReadFile(0)); 
    Thread ReadThread2 = new Thread(new ReadFile(1)); 
    Thread ReadThread3 = new Thread(new ReadFile(2)); 
    Thread ReadThread4 = new Thread(new ReadFile(3)); 
    Thread ReadThread5 = new Thread(new ReadFile(4)); 

    // starting all the threads 
    ReadThread1.start(); 
    ReadThread2.start(); 
    ReadThread3.start(); 
    ReadThread4.start(); 
    ReadThread5.start(); 

и ReadFile (который реализует Runnable, в методе выполнения, я пытаюсь синхронизировать на объекте bufferreader.

 BufferedReader br = null; 

      String sCurrentLine; 
      String filename="Source/"+files[fileno]; 
      br = new BufferedReader(new FileReader(filename)); 

      synchronized(br) 
      { 

      while ((sCurrentLine = br.readLine()) != null) { 
       int f=fileno+1; 
       System.out.print("File No."+f); 
       System.out.println("-->"+sCurrentLine); 
br.notifyAll(); 
// some thing needs to be dine here i guess 
}} 

Нужна помощь

+0

Вам не хватает части 'wait'. Но не на месте, которое вы указываете; в * верх * метода 'run'. –

+0

Звучит так, как будто вы ищете [Phaser] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Phaser.html) - особенно посмотрите на 'awaitPhase' код в этой ссылке. – OldCurmudgeon

+0

Надеюсь, вы можете легко выбрать следующий поток, чтобы иметь доступ к замку. В любом случае, если вам нужно только один поток, работающий в то время, почему у вас есть поток ... Вы должны перебрать файл, чтобы получить каждую строку. – Kazaag

ответ

2

отсутствует Вы много частей головоломки :

  • вы пытаетесь синхронизировать объект, локальный для каждого потока. e нет эффекта, и JVM может даже удалить всю операцию блокировки;

  • Вы выполняете notifyAll без согласования wait;

  • недостающее wait должен быть в верхней метода run, а не в нижней части, как вы указываете.

В целом, я боюсь, что исправление кода в этой точке выходит за рамки одного ответа StackOverflow. Мое предложение состоит в том, чтобы сначала ознакомиться с основными понятиями: семантикой замков в Java, как они взаимодействуют с wait и notify, и точной семантикой этих методов. Учебник Oracle по этому вопросу был бы хорошим началом.

+0

Я изменил объект, по которому мне нужно синхронизироваться. Я взял класс и синхронизировал его экземпляр. Но, все же не получилось, как я могу продолжить выполнение в round robin .. Я могу сделать взаимное исключение и полностью прочитать один файл одним потоком, затем начать следующий поток –

+1

Вы можете использовать переменную 'static', которая будет содержать номер файла, который следует читать дальше. Затем вы должны проверить это значение в каждом потоке для равенства с номером, который вы передаете в качестве аргумента конструктора. Это должно произойти в цикле 'wait', который является стандартной идиомой использования' wait' => легко googlable. –

3

Хотя это не идеальный сценарий для использования многопоточности, но поскольку это назначение, я помещаю одно решение, которое работает. Потоки будут выполняться последовательно, и есть несколько следует отметить:

  1. Текущий поток не может двигаться вперед, чтобы прочитать строку в файл до тех пор, и если его сразу предыдущий поток выполняется, как они должны читать в круговой системе мода.
  2. После того, как текущий поток будет выполнен, прочитав строку, он должен уведомить другую ветку еще, что поток будет ждать вечно.

Я протестировал этот код с некоторыми файлами в пакете temp, и он смог прочитать строки в круговой форме. Я считаю, что Phaser также может быть использован для решения этой проблемы.

public class FileReaderRoundRobinNew { 
     public Object[] locks; 

     private static class LinePrinterJob implements Runnable { 
      private final Object currentLock; 


private final Object nextLock; 
     BufferedReader bufferedReader = null; 

     public LinePrinterJob(String fileToRead, Object currentLock, Object nextLock) { 
      this.currentLock = currentLock; 
      this.nextLock = nextLock; 
      try { 
       this.bufferedReader = new BufferedReader(new FileReader(fileToRead)); 
      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
      } 
     } 

     @Override 
     public void run() { 
      /* 
      * Few points to be noted: 
      * 1. Current thread cannot move ahead to read the line in the file until and unless its immediately previous thread is done as they are supposed to read in round-robin fashion. 
      * 2. After current thread is done reading the line it must notify the other thread else that thread will wait forever. 
      * */ 
      String currentLine; 
      synchronized(currentLock) { 
       try { 
        while ((currentLine = bufferedReader.readLine()) != null) { 
         try { 
          currentLock.wait(); 
          System.out.println(currentLine); 
         } 
         catch(InterruptedException e) {} 
         synchronized(nextLock) { 
          nextLock.notify(); 
         } 
        } 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      synchronized(nextLock) { 
       nextLock.notify(); /// Ensures all threads exit at the end 
      } 
     } 
    } 

    public FileReaderRoundRobinNew(int numberOfFilesToRead) { 
     locks = new Object[numberOfFilesToRead]; 
     int i; 
     String fileLocation = "src/temp/"; 
     //Initialize lock instances in array. 
     for(i = 0; i < numberOfFilesToRead; ++i) locks[i] = new Object(); 
     //Create threads 
     int j; 
     for(j=0; j<(numberOfFilesToRead-1); j++){ 
      Thread linePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[j],locks[j+1])); 
      linePrinterThread.start(); 
     } 
     Thread lastLinePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[numberOfFilesToRead-1],locks[0])); 
     lastLinePrinterThread.start(); 
    } 

    public void startPrinting() { 
     synchronized (locks[0]) { 
      locks[0].notify(); 
     } 
    } 

    public static void main(String[] args) { 
     FileReaderRoundRobinNew fileReaderRoundRobin = new FileReaderRoundRobinNew(4); 
     fileReaderRoundRobin.startPrinting(); 
    } 
} 

Если единственная цель состоит в том, чтобы читать файлы в циклическом режиме, а не строго в том же порядке, то мы можем также использовать Phaser. В этом случае порядок чтения файлов не всегда одинаковый, например, если у нас есть четыре файла (F1, F2, F3 и F4), то в первой фазе он может читать их как F1-F2-F3-F4, но в следующем один может читать их как F2-F1-F4-F3. Я все еще делаю это решение для завершения.

public class FileReaderRoundRobinUsingPhaser { 

    final List<Runnable> tasks = new ArrayList<>(); 
    final int numberOfLinesToRead; 

    private static class LinePrinterJob implements Runnable { 
     private BufferedReader bufferedReader; 

     public LinePrinterJob(BufferedReader bufferedReader) { 
      this.bufferedReader = bufferedReader; 
     } 

     @Override 
     public void run() { 
      String currentLine; 
      try { 
       currentLine = bufferedReader.readLine(); 
       System.out.println(currentLine); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public FileReaderRoundRobinUsingPhaser(int numberOfFilesToRead, int numberOfLinesToRead) { 
     this.numberOfLinesToRead = numberOfLinesToRead; 
     String fileLocation = "src/temp/"; 
     for(int j=0; j<(numberOfFilesToRead-1); j++){ 
      try { 
       tasks.add(new LinePrinterJob(new BufferedReader(new FileReader(fileLocation + "Temp" + j)))); 
      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void startPrinting() { 
     final Phaser phaser = new Phaser(1){ 
      @Override 
      protected boolean onAdvance(int phase, int registeredParties) { 
       System.out.println("Phase Number: " + phase +" Registeres parties: " + getRegisteredParties() + " Arrived: " + getArrivedParties()); 
       return (phase >= numberOfLinesToRead || registeredParties == 0); 
      } 
     }; 

     for(Runnable task : tasks) { 
      phaser.register(); 
      new Thread(() -> { 
       do { 
        phaser.arriveAndAwaitAdvance(); 
        task.run(); 
       } while(!phaser.isTerminated()); 
      }).start(); 
     } 
     phaser.arriveAndDeregister(); 
    } 

    public static void main(String[] args) { 
     FileReaderRoundRobinUsingPhaser fileReaderRoundRobin = new FileReaderRoundRobinUsingPhaser(4, 4); 
     fileReaderRoundRobin.startPrinting(); 
     // Files will be accessed in round robin fashion but not exactly in same order always. For example it can read 4 files as 1234 then 1342 or 1243 etc. 
    } 

} 

Приведенный выше пример может быть изменен в соответствии с точным требованием. Здесь конструктор FileReaderRoundRobinUsingPhaser принимает количество файлов и количество строк для чтения из каждого файла.Также необходимо учитывать граничные условия.