2012-05-07 3 views
0

Хорошо использовать синхронизировать по java.io.File Объект. Если вы хотите альтернативно читать и записывать этот Файловый объект с использованием двух потоков: один для чтения и один для записи.Синхронизация по объекту java.io.File

public class PrintChar { 
    File fileObj; 
    public void read() { 

    while (true) { 
     synchronized (this) { 
      readFile(); 
      notifyAll(); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       System.out.println(Thread.currentThread().getName() 
         + " throws Exception"); 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

public void write(String temp) { 

    while (true) { 
     synchronized (this) { 
      writeFile(temp); 
      notifyAll(); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       System.out.println(Thread.currentThread().getName() 
         + " throws Exception"); 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

public void setFileObj(File fileObj) { 
    this.fileObj = fileObj; 
} 

public void readFile() { 
    InputStream inputStream; 
    try { 
     inputStream = new FileInputStream(fileObj); 
     // Get the object of DataInputStream 
     DataInputStream in = new DataInputStream(inputStream); 
     BufferedReader br = new BufferedReader(new InputStreamReader(in)); 
     String strLine; 
     // Read File Line By Line 
     while ((strLine = br.readLine()) != null) { 
      // Print the content on the console 
      System.out.println(strLine); 
     } 
     in.close(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

public void writeFile(String temp) { 
    BufferedWriter bw; 
    try { 
     bw = new BufferedWriter(new FileWriter(fileObj, true)); 
     bw.write(temp); 
     bw.newLine(); 
     bw.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

public static void main(String args[]) { 

    final PrintChar p = new PrintChar(); 
    p.setFileObj(new File("C:\\sunny.txt")); 

    Thread readingThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      p.read(); 
     } 
    }); 
    Thread writingThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      p.write("hello"); 
     } 
    }); 

    Thread Randomizer = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (true) 
       try { 
        Thread.sleep(500000); 
       } catch (InterruptedException e) { 
        System.out.println(Thread.currentThread().getName() 
          + " throws Exception"); 
        e.printStackTrace(); 
       } 
     } 
    }); 

    readingThread.start(); 
    writingThread.start(); 
    Randomizer.start(); 
} 

}

В коде выше я использовал Синхронное (это), Могу ли я использовать Synchronize (fileObj) ??

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

+1

Пожалуйста, отредактируйте ваш вопрос, чтобы предоставить нам более подробную информацию. Показать пример кода? Как вы читаете или записываете файл? – Gray

+0

Ваш профессор предлагает вам избежать этой проблемы, только выполняя одну операцию ввода-вывода за раз, в специальном потоке ввода-вывода, который получает работу из очереди FIFO. Это все равно не будет работать, если вы используете несколько объектов для ссылки на один и тот же базовый физический файл, но это устраняет необходимость блокировки, если остальная часть программы верна. Вы также должны быть осторожны (так же, как и без FIFO) об управлении порядком операций ввода-вывода в физическом файле. Если у вас есть поток, выполняющий чтение при смещении 0 и другой записи со смещением 0, какой файл ввода-вывода происходит первым? –

+0

@Steve Я хочу сначала прочитать, а затем написать. Спасибо за ваши ценные комментарии. –

ответ

2

В общем, блокировка по I/O - отличная идея. Лучше построить свою программу таким образом, чтобы вы гарантировали по дизайну, что обычно данный раздел файла не одновременно записывается и читается, а только блокируется, если вы абсолютно должны посредничать между чтением и записью данного фрагмента файла.

3

Edit:

Теперь, когда вы добавили код, вы можете замок на fileObj, но только если оно не изменено. Я бы переместил его в конструктор и сделал его final, чтобы убедиться, что кто-то не вызывает setFileObj неуместно. Либо это, либо исключение, если this.fileObj не null.

Пара Другие комментарии:

  • Не используйте notifyAll(), если вам действительно нужно уведомить несколько потоков.
  • Если вы поймаете InterruptedException, я бы оставил нить вместо цикла. Всегда принимайте правильные решения в отношении ловли InterruptedException и не просто печать и петля.
  • Ваш in.close(); должен быть в блоке finally.

Вы можете заблокировать любой объект, который вы хотите до тех пор, пока обе нити замок на одной и той же константного объекта. Это типично использовать private final объект, например:

private final File sharedFile = new File(...); 

    // reader 
    synchronized (sharedFile) { 
     // read from file 
    } 
    ... 

    // writer 
    synchronized (sharedFile) { 
     // write to file 
    } 

Что вы не может сделать замок на двух различных File объектов, даже если они указывают на один и тот же файл. Ниже будет не работы, например:

private static final String SHARED_FILE_NAME = "/tmp/some-file"; 

    // reader 
    File readFile = new File(SHARED_FILE_NAME); 
    synchronized (readFile) { 
     ... 
    } 

    // writer 
    File writeFile = new File(SHARED_FILE_NAME); 
    synchronized (writeFile) { 
     ... 
    } 

Кроме того, только потому, что вы замок на той же File объекта не означает, что чтение и написание кода будет работать между потоками. Вам нужно будет убедиться, что в писателе все обновления будут очищены в синхронизированном блоке. В читателе вы, вероятно, не хотите использовать буферизованные потоки, иначе у вас будут устаревшие данные.

+0

Я добавил исходный код к моему Вопросу, пожалуйста, проверьте –

+0

Спасибо за комментарии к обзору. Любые комментарии к выделенной жирной строке, которую я добавил –

+0

[Почему вы рекомендуете] (http://stackoverflow.com/a/3186336/1103872) 'уведомлять' против' notifyAll'? Последнее не может повредиться, если в наборе ожидания есть только один поток, но первый может вызвать всевозможные странные ошибки, если есть несколько потоков. –

0

Обычно нет.Есть намного лучшие способы: Используйте ReentrantLock

Этот класс уже предлагает метафору «блокировка для чтения/записи». Он также правильно обрабатывает случай, когда многие потоки могут читать одновременно, но может писать только один поток.

Как уже упоминалось, блокировка будет работать только в том случае, если все потоки используют один и тот же экземпляр File.

Убедитесь, что вы сбросили выходные буферы после каждой записи; это будет стоить некоторой производительности, но в противном случае вы получите устаревшие чтения (read thread не найдет данные, которые вы ожидаете там).

Если вы хотите упростить код, добавьте третий поток, который принимает команды от двух других. Команды: READ и WRITE. Поместите команды в очередь и дайте 3-му потоку ждать записей в очереди. Каждая команда должна иметь метод обратного вызова (например, success()), который будет вызываться 3-м потоком, когда команда будет выполнена.

Таким образом, вам вообще не нужна фиксация. Код для каждого потока будет намного проще и легко тестировать.

[EDIT] ответа на основе кода: Она будет работать в вашем случае, потому что каждый использует тот же экземпляр fileObj, но было бы смешивать несколько вещей в одно поле. Люди, читающие ваш код, ожидают, что файл-объект будет всего лишь способом чтения файла. Таким образом, решение нарушит principle of least astonishment.

Если вы утверждаете, что это сэкономит память, я отвечу «premature optimization».

Попробуйте найти решение, которое четко свяжет ваши намерения. «Умная» кодировка хороша для вашего эго, но это единственная положительная вещь, которую можно сказать об этом (и это не хорошо для вашего эго, чтобы узнать, что люди скажут о вас после того, как они впервые видят ваш «умный» код ...) ;-)

+0

Спасибо за ответ, я кое-что изменил в своем Вопросе. Не могли бы вы проверить, я думаю, что это похоже на то, что вы пытаетесь сказать. Пожалуйста, дополните –

0

Очередь от чтения/записи объектов в один поток, который затем выполняет операцию, является действительным подходом к чему-то, но я не уверен, что.

Какой бы он не сделал, например, чтобы обеспечить соблюдение порядка чтения/записи/чтения/записи, как вы указали в своем предыдущем вопросе. Нет ничего, что могло бы остановить чтение потока с очередью 100 запросов на чтение.

Это можно предотвратить, если поток, который отправляет объект на него, до тех пор, пока он не будет передан потоком чтения/записи, но это кажется очень сложным способом обеспечения соблюдения порядка чтения/записи (предполагая, что это то, что вы все еще хочу).

Я сейчас добираюсь до штата, где я не уверен, что вам нужно/нужно.

Смежные вопросы