2010-01-11 4 views
12

У меня есть несколько потоков (некоторые из которых порождаются процессом X, другие - процессом Y, и так далее), и каждый поток необходимо записать в файл MyFile. Однако, если Thread T1 начинает писать в MyFile первый, а затем, когда Thread T2 начинает писать, он должен ждать T1 к релиза файла, так что он может прочитать содержимое, написанные в Thread T1. Другими словами, каждый поток будет иметь метод finalizeThread, например, так:Блокировка файлов Java

private void finalizeThread() { 
    File f = new File("MyFile.dat"); 
    f.createNewFile(); // atomically creates the file, if it doesn't exist 
    locked_section { 
     readContentsFromFile(f); // read contents if some other thread already modified the file 
     modifyContentsFromFile(f); // modify 
     writeFile(f); // write, so that new threads can see the content modified by this thread 
    } 
} 

Мой вопрос: Как я могу выполнить locked_section в приведенном выше коде? Я изучал класс FileLock, но он говорит в Javadoc, что «Блокировки файлов хранятся от имени всей виртуальной машины Java. Они не подходят для управления доступом к файлу несколькими потоками на той же виртуальной машине»..

+0

Вы уверены, что действительно хотите использовать метод finalize()? – Dmitry

+0

Нет, имя метода фактически не завершено. Это метод/обратный вызов, который вызывается после потока (на самом деле, набор потоков, но это не имеет значения для случая) завершается его работой, поскольку я не использую стандартные потоки API Java Concurrency. Я собираюсь переименовать его, чтобы избежать путаницы с 'Object # finalize'. –

ответ

12

Если файл доступен только из вашей программы, синхронизированный объект блокировки в порядке. Но если вы хотите защитить файл от изменений другими программами во время работы над ним, вы можете использовать функции блокировки файлов Java в java.nio.channels.FileLock (example). Как говорится в тексте, помните, что в некоторых операционных системах программы все равно могут изменять файлы, если они не проверяют наличие существующей блокировки файлов.

+0

Спасибо за отзыв. Да, он доступен только моей программе, и каждый поток будет/может проверить наличие блокировки перед продолжением. Проблема в том, что API, который я использую, может порождать потоки из нескольких разных процессов, а некоторые потоки из одних и тех же процессов, и я боюсь, что с этим могут возникнуть проблемы, так как javadoc 'FileLock' упоминает об этом. –

+0

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

+2

Javadoc говорит: «Файловые блокировки хранятся от имени всей виртуальной машины Java.Они не подходят для контроля доступа к файлу несколькими потоками на одной и той же виртуальной машине. Объекты блокировки файлов безопасны для использования несколькими параллельными потоками. » Не два последних предложения, взаимно исключающие? Я думаю, кому-то придется взглянуть на исходный код ... В следующем абзаце это говорит: «Этот API-интерфейс для блокировки файлов предназначен для непосредственной привязки к собственному блокирующему устройству базовой операционной системы». Поэтому он * должен * работать так же, как flock (Linux) или LockFileEx (Windows). – AndiDog

0

Вы хотите синхронизировать некоторые объекты. Например:

synchronized(fileLockObject) { 
    readContentsFromFile(f); 
    modifyContentsFromFile(f); 
    writeFile(f); 
} 
+1

Привет, Анон, спасибо за ваш комментарий. Однако я не могу этого сделать, поскольку эти потоки порождаются разными процессами, и я не могу поделиться этим объектом среди всех потоков, следовательно, нужен другой подход. Это также не стандартные потоки Java 'concurrency. *', А потоки, созданные Oracle API. –

+0

Если это разные процессы (и, следовательно, отдельные виртуальные машины), вы можете просто использовать класс 'FileLock'. –

+0

Да, но некоторые порождаются одним и тем же процессом. Но да, возможно, гибридная стратегия будет работать. Благодарю. –

2

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

+1

Если вы собираетесь использовать центральный процесс, вероятно, лучше, если этот процесс обрабатывает само чтение/запись, поэтому вам не нужно беспокоиться о том, что происходит, когда нить умирает после того, как вы выпустили блокировку (ну, вы делаете, но это менее сложно). – wds

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