加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

使用volatile来确保Java中共享(但不是并发)数据的可见性

发布时间:2020-12-15 04:19:45 所属栏目:Java 来源:网络整理
导读:我正在尝试实现LZ77的快速版本,我有一个问题要问你关于并发编程的问题. 现在我有一个最终的byte []缓冲区和一个最终的int [] resultHolder,它们都有相同的长度.该计划执行以下操作: 主线程写入所有缓冲区,然后通知线程并等待它们完成. 单个工作线程处理缓冲
我正在尝试实现LZ77的快速版本,我有一个问题要问你关于并发编程的问题.

现在我有一个最终的byte []缓冲区和一个最终的int [] resultHolder,它们都有相同的长度.该计划执行以下操作:

>主线程写入所有缓冲区,然后通知线程并等待它们完成.
>单个工作线程处理缓冲区的一部分,将结果保存在结果持有者的同一部分中.工人的部分是独家的.之后,通知主线程并且工作人员暂停.
>当所有工作人员暂停时,主线程读取resultHolder中的数据并更新缓冲区,然后(如果需要)该过程再次从第1点开始.

manager(主线程)中的重要事项声明如下:

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只是包装一个volatile字段并提供两种方法:一种用于读取它,另一种用于写入它.

Worker的run()代码:

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字段会刷新所有以前更改的数据,然后从另一个线程读取它会使它们可见.

那么在这种情况下是否足以确保正确的可见性?从来没有真正的并发访问相同的内存区域,因此volatile字段应该比ReadWriteLock便宜很多.

解决方法

你甚至不需要volatile,因为 BlockingQueues已经提供了必要的内存可见性保证:

Memory consistency effects: As with other concurrent collections,actions in a thread prior to placing an object into a BlockingQueue 07001 actions subsequent to the access or removal of that element from the BlockingQueue in another thread.

通常,如果您已经进行了某种同步,则可能不需要执行任何特殊操作来确保内存可见性,因为它已经由您使用的同步原语保证.

但是,当您没有显式同步时(例如,在无锁算法中),可以使用易失性读取和写入来确保内存可见性.

P. S.

此外,您似乎可以使用CyclicBarrier代替您的队列解决方案,它专门针对类似场景而设计.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读