2017-02-21 16 views
1

У меня проблема с синхронизированным чтением моего файла. Случай прост: обрабатывать данные в файле. Моя проблема - синхронизация. Я пытаюсь сделать это на объектном читателе класса BufferedReader, но у меня две проблемы. Если я инициализирую читателя в «try with resourses» моего метода read(), я перейду к различным объектам BufReader для одного и того же объекта, когда буду использовать его в разных ададах. Второй я инициализирую его в классе и получаю тот же объект для потоков, но большую проблему с исключениями и непредсказуемым поведением. Я напишу код для второй ситуации. Можете ли вы посоветовать мне, как решить. Я сейчас учусь, вот почему я хочу советов.Проблемы многопоточности Java

class FileReaderClass { 
    private File file = new File("src\\exer1\\Transfers.txt"); 
    private BufferedReader reader = null; 
    private FileReader fr = null; 

    StringBuilder sb = new StringBuilder(); 

    void read() throws IOException { 
     try { 
      fr = new FileReader(file); 
      reader = new BufferedReader(fr); 
      String buftext; 
       while ((buftext = reader.readLine()) != null){ 
        synchronized (reader) { 
         System.out.println(Thread.currentThread().getName());//for testing 
         sb.append(buftext).append("\n"); 
         //System.out.println(buftext); 
        } 
       } 
      } 
     catch (IOException e) { 
      e.printStackTrace(); 
     } 
     finally { 
      if (reader != null) 
       reader.close(); 
      if (fr != null) 
       fr.close(); 
     } 
    } 
} 

class Reader1 implements Runnable { 

    private FileReaderClass frc; 

    public Reader1(FileReaderClass frc) { 
     this.frc = frc; 
    } 

    @Override 
    public void run() { 
     try { 
      frc.read(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
public class Ex1 { 
    public static void main(String[] args) throws InterruptedException { 
     FileReaderClass frc = new FileReaderClass(); 
     Thread t1 = new Thread(new Reader1(frc)); 
     Thread t2 = new Thread(new Reader2(frc)); 

     t1.start(); 
     t2.start(); 
     t1.join(); 
     t2.join(); 
     System.out.println("---------------------"); 
     System.out.println(frc.sb); 

    } 
} 
+0

Что вы хотите сделать? У вас есть только один открытый файл? Только один читается для одного и того же файла одновременно? –

+0

Да, я хочу только читать сейчас. Другая логика - следующий шаг. Но я хочу прочитать так, чтобы одна строка из файла была прочитана и записана в Stringbuilder за один раз. И я хочу сделать его параллельным в нескольких потоках. Случай параллельной обработки файла. –

+0

В этом случае, @ Selçuk Cihan является правильным. синхронизация отсутствует. Вы можете пойти с помощью try-with-resource. Каждый созданный FileReaderClass будет иметь свой собственный FileReader, и он хочет, чтобы вы захотели. Но чтобы иметь параллельную обработку файла, я думаю, что ваши читатели файлов должны читать другую часть файла, и вам придется конкатенировать конечные результаты. Это имеет смысл. –

ответ

0

Вы разделяете тот же FileReaderClass экземпляр (т.е. frc) в двух потоках. Ваш FileReaderClass не является потокобезопасным, что вызывает проблемы. Здесь есть две альтернативы:

  • Создайте еще один экземпляр FileReaderClass, так что оба потока будут использовать разные экземпляры.
  • Отметить метод read как snychronized.

Вы синхронизируетесь на неправильном уровне. Ваш защитник синхронизации бесполезен, так как на самом деле есть два reader s. Это потому, что каждый раз вызывается read, будет создан reader, который будет отдельным экземпляром. Мы не можем даже точно знать, какой экземпляр был предметом синхронизации.

+0

Но могу ли я сделать общий экземпляр BufferedReader для FileReaderClass? Я попытался это сделать, но это вызывает IOExeption. Я знаю, что исключения в конструкторе классов - это плохая практика. Спасибо за ваш ответ. Я понял это. –

+0

@GuluevRuslan Я не уверен, что методы BufferedReader являются потокобезопасными, поэтому я бы не советовал использовать один и тот же экземпляр «BufferedReader» одновременно из нескольких потоков. Вам действительно нужно прочитать файл многопоточным? Большую часть времени узкое место не читает ввод, скорее это обработка данных, которые на самом деле хотелось бы распараллелить. Возможно, вам стоит пересмотреть вопрос о параллелизированном вводе. –

0

Если вы хотите распараллелить чтение своего файла, вы должны использовать тот же самый читатель, но использовать надлежащую синхронизацию для каждого чтения любым потоком, чтобы он оставался последовательным, самый простой способ - сделать весь метод чтения синхронизированным и создать экземпляр читателей в вашем конструкторе классов.

Поскольку вы можете читать и писать в построитель строк в правильном порядке, поток, который читает строку, должен только освобождать блокировку после ее записи в StringBuilder, что делает весь ваш метод достаточно защищенным блокировкой , Он будет работать, но вы не получите никакой производительности, а для небольших файлов это может вызвать слишком много накладных расходов, но в качестве упражнения это может быть достаточно.

Ваш код, как это имеет следующие проблемы

  1. Вы всегда создание новых читателей, при этом каждый поток вызова этого метода будет начать с самого начала.
  2. Как уже было сказано другим ответом, вы синхронизируете себя на неправильном уровне, любой поток может читать, и планировщик потоков может приостановить его сразу же после того, как ваша запись в объект StringBuilder будет неработоспособной (я думаю, что она не предназначена) ,
Смежные вопросы