3

У меня есть 2 потока, которые одновременно обращаются к тому же большому файлу (.txt).java Память сопоставлена ​​Файлы многопоточность чтение/запись

1-я нить читается из файла. Вторая нить записывает в файл.

Оба потока обращаются к одному и тому же блоку, например. (Старт: 0, размер блока: 10), но с различных каналов & Buffer экземпляров

Читатель:

{ 
    int BLOCK_SIZE = 10; 
    byte[] bytesArr = new byte[BLOCK_SIZE]; 
    File file = new File("/db.txt"); 
    RandomAccessFile randomFile = new RandomAccessFile(file, "r"); 
    FileChannel channel = randomFile.getChannel(); 
    MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, BLOCK_SIZE); 
    map.get(bytesArr , 0, BLOCK_SIZE); 
    channel.close(); 
} 

Автор:

{ 
    int BLOCK_SIZE = 10; 
    File file = new File("/db.txt"); 
    RandomAccessFile randomFile = new RandomAccessFile(file, "rw"); 
    FileChannel channel = randomFile.getChannel(); 
    MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, BLOCK_SIZE); 
    map.put(bytesToWrite); 
    channel.close(); 
} 

Я знаю, что если оба начинается в одно и то же время, я получу Overlapping Exceptions! НО, что я хотел бы знать, в какой момент именно переплетение происходит? Я имею в виду, когда происходит «блокировка» точно? Пример: позволяет сказать, что доступ к писателю ПОЛУЧИТЬ первый, а затем, если читатель попытаться получить доступ, в какой момент это возможно ?:

FileChannel channel = randomFile.getChannel(); 
// 1- can reader access here? 
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, BLOCK_SIZE); 
// 2- can reader access here? 
map.put(bytesToWrite); 
// 3- can reader access here? 
channel.close(); 
// 4- can reader access here? 

1, 2, 3 или 4?

№ 4 уверен, потому что канал закрыт! Как насчет других точек?

Спасибо!

+0

Я не вижу блокировки в вашем коде. –

+0

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

+0

@ChrisK, я могу дать вам пример использования, но вы знакомы с JSF ManagedBeans? –

ответ

2

Я суммирую несколько заметок из беседы чата с OP. У ОП была ментальная модель (как и большинство из нас), которая, как только поток записывает в структуру данных, эта структура данных сразу видима для всех других потоков. В тестах OPs с использованием файлов с отображением памяти он подтвердил, что это оказалось правдой на одном процессоре Intel.

К сожалению, это неправда, и это область, где Java может показывать и демонстрировать основное поведение аппаратного обеспечения. Java была спроектирована так, чтобы предположить, что код является однопоточным и может быть оптимизирован как таковой до тех пор, пока не будет сказано иначе. То, что это значит, будет отличаться аппаратным обеспечением и версией точки доступа (и статистикой, которую собирает горячая точка). Эта сложность и работа в одном сокетном процессоре Intel недействила тест OPs.

Для получения дополнительной информации следующие ссылки помогут получить более глубокое понимание «модели памяти Java». И, в частности, синхронизация означает не просто «взаимное исключение»; в аппаратных терминах это также касается «видимости данных» и «упорядочения инструкций». Две темы, которые однопоточный код принимают как должное.

Не беспокойтесь, если это занимает много времени, чтобы погрузить в и что вы чувствуете себя разбитым на первый. Сначала все это было так.Java делает удивительную работу по скрыть эту сложность, если и только если вы выполните это одно простое правило. Когда поток читает или изменяет общую структуру данных, он должен находиться в синхронизированном блоке. То есть как поток записи, так и поток чтения. Очевидно, я упрощаю, но следую этому правилу, и программа всегда будет работать. Разбейте его только в том случае, если у вас есть глубокое понимание модели памяти Java, барьеров памяти и того, как она относится к различным аппаратным средствам (и даже тогда эксперты параллелизма даже не нарушают это правило, если могут: однопоточная передача часто намного проще и может быть surprisingly fast .. многие системы с низкой задержкой предназначены для того, чтобы быть в основном однопоточными по этой причине).


Чтобы непосредственно ответить на вопрос ОП. В примере кода из вопроса нет блокировок. Никаких барьеров памяти, никаких средств параллелизма вообще. Таким образом, поведение того, как будут взаимодействовать чтения и записи, не определено. Они могут работать, они не могут. Они могут работать большую часть времени. У Intel самые сильные гарантии памяти для всех процессоров, а также запуск тестовых примеров на одном разъеме. Процессор Intel пропустит множество сложных ошибок. Солнце было уловлено этим еще до того, как появились Java 5 и JSR 133 (прочитайте статью о том, почему Double Checked Locking было разбито на Java для более подробной информации).

+0

Большое спасибо за вашу большую помощь. ссылки, которые вы разместили о Java Memory Model и Memory Barrier, очень полезны. несмотря на то, что я спрашивал о том, что я собираюсь прочитать/написать тот же блок (часть) байтов из/в MappedByteBuffers, и все предложения/ответы идут в другом направлении (возможно, из-за моего плохого сформулированного Вопроса), но это привело меня к тому, что мне нужно больше узнать о взаимодействии между JVM, памятью, системой и оборудованием. –

+0

Действительно ли этот ответ действительно действителен? Насколько я знаю, карты памяти сопоставлены. Они обрабатываются os, например, mmap на системе posix. Они гарантируют какое-то особое поведение. Например, если вы изменили бит, генерируется ошибка страницы, и os меняет эту страницу с диска на память и наоборот. – slowjack2k

1

Вы не получите любых исключений за исключением этого кода или любых блоков. Файловые блокировки работают между процессами, а не между потоками. Здесь вам понадобятся синхронизация, семафоры или ReadWriteLocks. И нет необходимости использовать два канала.

+0

спасибо за ваш ответ, но не могли бы вы дать мне Usecase, где происходит перекрытие? –

+0

@ Rami.Q Что вы подразумеваете под перекрытием? Если вы не используете какой-либо барьер памяти в своем параллельном коде, вы не поймете, что будет видно в потоке чтения. Это могут быть данные, которые были записаны, это могут быть данные, прежде чем они были записаны, или это могут быть данные, частично написанные и, следовательно, в поврежденном состоянии. –

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

  • Нет связанных вопросов^_^