Use volatile to ensure the visibility of shared (but not concurrent) data in Java

I'm trying to implement a fast version of LZ77. I have a question for you about concurrent programming

Now I have a final byte [] buffer and a final int [] resultholder, both of which have the same length The plan does the following:

>The main thread writes all buffers, then notifies the threads and waits for them to complete. > A single worker thread processes a portion of the buffer and stores the result in the same portion of the result holder The workers' part is exclusive After that, the main thread is notified and the worker pauses. > When all workers pause, the main thread reads the data in the resultholder and updates the buffer, and then (if necessary) the process starts from point 1 again

The important items in the manager (main thread) are declared as follows:

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 just wraps a volatile field and provides two methods: one for reading it and the other for writing it

Worker's run() Code:

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) { }
}

Finally, an important part of the main thread:

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();
}

The synchronization effect on arrayblockingqueue is very good I suspect using readvolatile() and writevolatile() I was told that writing a volatile field would refresh all previously changed data, and then reading it from another thread would make them visible

Is it sufficient to ensure correct visibility in this case? There has never been a real concurrent access to the same memory area, so the volatile field should be much cheaper than readwritelock

Solution

You don't even need volatile because blockingqueues already provides the necessary memory visibility:

In general, if you have some kind of synchronization, you may not need to do anything special to ensure memory visibility because it is guaranteed by the synchronization primitive you use

However, when you do not have explicit synchronization (for example, in a lockless algorithm), volatile reads and writes can be used to ensure memory visibility

P. S.

In addition, it seems that you can use cyclicbarrier instead of your queue solution, which is specially designed for similar scenarios

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>