Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Синхронизация доступа


Автор: zss 12.2.2005, 23:56
Есть 2 потока. Один читае файл, а другой пишет. Как синхронизировать доступ к файлу ?

Автор: LSD 13.2.2005, 00:12
Простейший способ, хотя и не самый оптимальный:
Код
Object LOCK = new Object();
....
synchronized(LOCK)
{
//делаем здесь ВСЕ манипуляции с файлом
}

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

Автор: zss 13.2.2005, 09:57
Смысл такой - читающий поток проверяет дату последнего изменения файла. Если она изменилась, то он читает его. Пишуший поток просто пишет через определенные период времени.

Автор: Domestic Cat 13.2.2005, 10:16
Тогда можно сделать как LSD предлагает, только учти что lock должен быть один и тот же для обеих тредов

Код

public static final Object LOCK = new Object();

...
// тред 1
synchronized(LOCK)
{
  проверяем дату
}
...
// тред 2
synchronized(LOCK)
{
    пишем в файл
}

Автор: zss 13.2.2005, 10:41
Наверное так не получится - эти потоки находятся в разных приложениях.

Тоесть они могут запускаться независимо друг от друга.

Может это можно сделать средствами самого файла ?

Автор: LSD 13.2.2005, 10:56
Цитата(zss @ 13.2.2005, 10:41)
Может это можно сделать средствами самого файла ?

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

Автор: djGri 21.2.2005, 18:44
public void syncronized read() throws .... {
// insert code here
}
public void syncronized write() throws ....{
// insert code here
}

Автор: Domestic Cat 21.2.2005, 18:56
Цитата
public void syncronized read() throws .... {
// insert code here
}
public void syncronized write() throws ....{
// insert code here
}


Все это не должно принадлежать этим двум тредам.

Пожалуйстa пользуйся тегами [codе=javа] [/code].

Автор: Zandr 26.2.2005, 10:20
Цитата
Есть 2 потока. Один читае файл, а другой пишет. Как синхронизировать доступ к файлу ?

Цитата
Наверное так не получится - эти потоки находятся в разных приложениях.
Тоесть они могут запускаться независимо друг от друга.

Пока не оказалось, что это вообще разные файлы на разных машинах, предложу следующее (это просто кусок из моего кода, не адаптированный под текущий вопрос):
Код

...
FileInputStream fis = new FileInputStream( ...);
FileChannel chan = fis.getChannel();
FileLock lock = chan.tryLock(0, Long.MAX_VALUE, true);
if (lock == null) {
   System.out.println( "Другой процесс использует файл");
} else {
   ...
   lock.release();
}
fis.close();
...

Автор: Guest 28.2.2005, 09:24
Цитата(Zandr @ 26.2.2005, 10:20)
Пока не оказалось, что это вообще разные файлы на разных машинах


smile

Это один файл на одной машине (PC1), но читатель и писатель на разных (PC2 и PC3)

Тоесть участвуют 2 разные машины для манипуляцией файлом, а сам он лежит на третьей (например на сервере)

Автор: zss 28.2.2005, 09:25
извиняюсь - не зашел smile

Автор: Zandr 28.2.2005, 14:32
Значит юзай блокировки на уровне файловой системы, как в примере выше (я его попровил немного). Там осуществляется попытка блокировки на запись. Остальное в API.

Автор: zss 28.2.2005, 16:49
Что-то не очень-то получается

если блокировать и читающий процесс и пишущий, то вроде все должно работать, но все равно слетает smile

Автор: Zandr 2.3.2005, 08:41
Не, процессы блокировать не нужно. Блокировать нужно файлы smile Если твой процесс читает файл - есть смысл заблокировать файл на изменение, если твой процесс пишет в файл, то есть смысл заблокировать файл вообще. Естественно что нужно аккуратно все это делать. Заблокировать можно не весь файл, а только его часть. Блокировка (которая выше) работает не на уровне Java-машины, а на уровне операционки. Поэтому если блокируешь файл на доступ, то другие программы не могут его прочитать не зависимо от того на каком языке они написаны. Есть криво написанные программы, которые не блокируют файлы, обрабатывающиеся продолжительное время.

Цитата
все равно слетает

В какую сторону?

Автор: zss 12.3.2005, 15:37
Пробовал тестовый вариант, в котором при чтении файл блокируется для изменения, а при записи монопольно - вроде все работает. Непонятно, почему при чтении тоже нельзя монопольно заблокировать ?

Код

java.nio.channels.NonWritableChannelException
    at sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:784)
    at java.nio.channels.FileChannel.tryLock(FileChannel.java:967)



Тестовый вариант

Код

public class Lock {

    private static String filePath = "C:\\test.txt";
    private static File file = new File (filePath);

    public Lock() {
        readFile();        
        writeFile();                
    }

    public void readFile (){

        try {

           
            FileInputStream stream = new FileInputStream ( file );
            FileChannel chan = stream.getChannel ();
            FileLock lock = chan.tryLock (0, Long.MAX_VALUE, true);
            if ( lock == null ) {
                System.out.println ( "Файл заблокирован на запись" );
                return;
            }
            else {
//                lock.release ();
//                chan.close();
//                stream.close ();
            }

        }
        catch ( Throwable t ) {
            t.printStackTrace ();
        }

    }

    public void writeFile(){
        try {

            StreamResult outStream = new StreamResult ( file );
            
            
            FileOutputStream stream = new FileOutputStream ( file );
            FileChannel chan = stream.getChannel ();
            FileLock lock = chan.tryLock ();
            if ( lock == null ) {
                System.out.println ( "Файл заблокирован на чтение" );
                return;
            }
            else {
//                stream.write(-1);
//                lock.release ();
//                chan.close();
//                stream.close ();
            }

        }

        catch ( Throwable ex ) {
            ex.printStackTrace ();
        }

    }


    public static void main(String[] args) {
        Lock lock = new Lock ();
    }

}



И самое главное. Это все работает при FileInputStream & FileOutputStream. Но мне надо при записи использовать StreamResult - а с ним к сожалению не получится получить FileChannel. Как быть ?

Думал прокатит так
Код

            FileOutputStream stream = new FileOutputStream (file);
            StreamResult out = new StreamResult ( stream );            
            FileChannel chan = stream.getChannel ();
            FileLock lock = chan.tryLock ();
            if ( lock == null ) {
                System.out.println ( "Файл заблокирован на чтение" );
                return;
            }
            else {
    transformer.transform ( source, out );
                lock.release ();
                chan.close();
                stream.close ();
            }



Но не дает писать - говорит файл заблокирован

P.S. Блин - задолбался с этой синхронизацией, что нельзя было просто сделать что-нибудь вроде Mutex

Автор: zss 13.3.2005, 15:52
Баг нашел - я не всегда закрывал поток.

Только вот вопрос - когда я открываю файл FileOutputStream (...), проверяю его блокировку и если файл заблокирован, то просто закрываю поток. Но при этом все данные файла теряются.
Если открывать FileOutputStream (..., true) - то происходит дозапись файла.


1. Как открывая FileOutputStream, если ничего не надо делать с файлов - вернуть данные при его закрытии ?
2. Или наоборот - открывая FileOutputStream (..., true) при необходимости изменения файла сначала почистить его, чтоб не дописывать ?

Автор: Domestic Cat 13.3.2005, 18:47
Модератор: один топик - один вопрос
Цитата
Как открывая FileOutputStream, если ничего не надо делать с файлов - вернуть данные при его закрытии ?

В ByteArrayOutputStream есть метод toByteArray, он пишет содержимое буфера в массив. Так что если сделать большой буфер, должно работать.

Автор: Zandr 15.3.2005, 09:59
У тебя lock нулевой становится или transformer.transform ( source, out ); писать не может?
Если второе, то такого быть не может smile А если первое, то значит кто-то наложил блокировку (неважно - на чтение или на запись) на этот файл (или любую его часть) и пока еще ее не освободил. А mutex по-моему совсем для других целей....

Опа... не заметил вторую страницу... smile smile smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)