Я пытаюсь реализовать быструю версию LZ77, и у меня есть вопрос, чтобы спросить вас о параллельном программировании.Использование volatile для обеспечения видимости общих (но не одновременных) данных в Java
На данный момент у меня есть final byte[] buffer
и final int[] resultHolder
, оба одинаковой длины. Программа выполняет следующие действия:
Основной поток записывает весь буфер, затем уведомляет о потоках и ждет их завершения.
Единственная рабочая нить обрабатывает часть буфера, сохраняя результаты в той же части результирующего держателя. Часть работника является исключительной. После этого основной поток уведомляется, и рабочий останавливается.
Когда все рабочие паузы, основной поток считывает данные в resultHolder и обновляет буфер, а затем (при необходимости) процесс начинается снова с точки 1.
Важные вещи в менеджере (Основная тема) объявлена следующим образом:
final byte[] buffer = new byte[SIZE];
final MemoryHelper memoryHelper = new MemoryHelper();
final ArrayBlockingQueue<Object> waitBuffer = new ArrayBlockingQueue<Object>(TOT_WORKERS);
final ArrayBlockingQueue<Object> waitResult = new ArrayBlockingQueue<Object>(TOT_WORKERS);
final int[] resultHolder = new int[SIZE];
MemoryHelper просто оборачивает летучее поле и предоставляет два метода: один для чтения его и один для записи на него. пробег (код)
работника:
public void run() {
try {
// Wait main thread
while(manager.waitBuffer.take() != SHUTDOWN){
// Load new buffer values
manager.memoryHelper.readVolatile();
// Do something
for (int i = a; i <= b; i++){
manager.resultHolder[i] = manager.buffer[i] + 10;
}
// Flush new values of resultHolder
manager.memoryHelper.writeVolatile();
// Signal job done
manager.waitResult.add(Object.class);
}
} catch (InterruptedException e) { }
}
Наконец, важная часть главного Тема:
for(int i=0; i < 100_000; i++){
// Start workers
for (int j = 0; j < TOT_WORKERS; j++)
waitBuffer.add(Object.class);
// Wait workers
for (int j = 0; j < TOT_WORKERS; j++)
waitResult.take();
// Load results
memoryHelper.readVolatile();
// Do something
processResult();
setBuffer();
// Store buffer
memoryHelper.writeVolatile();
}
Синхронизация на ArrayBlockingQueue работает хорошо. Я сомневаюсь в использовании readVolatile()
и writeVolatile()
. Мне сказали, что запись в нестабильное поле сбрасывает в память все ранее измененные данные, после чего чтение из другого потока делает их видимыми.
Итак, достаточно ли в этом случае обеспечить правильную видимость? Не существует реального одновременного доступа к тем же областям памяти, поэтому поле volatile должно быть намного дешевле, чем ReadWriteLock.
См. Также http://stackoverflow.com/questions/17108541/happens-before-relationships-with-volatile-fields-and-synchronized-blocks-in-jav – Raedwald