Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用volatile确保Java中共享(但不是并发)数据的可见性_Java_Multithreading_Concurrency_Volatile_Memory Visibility - Fatal编程技术网

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

使用volatile确保Java中共享(但不是并发)数据的可见性,java,multithreading,concurrency,volatile,memory-visibility,Java,Multithreading,Concurrency,Volatile,Memory Visibility,我正在尝试实现LZ77的快速版本,我有一个关于并发编程的问题要问你 现在我有一个final byte[]buffer和一个final int[]resultHolder,两者的长度相同。该程序执行以下操作: 主线程写入所有缓冲区,然后通知线程并等待它们完成 单个工作线程处理缓冲区的一部分,将结果保存在结果保持器的相同部分中。工人部分是专用的。在此之后,主线程被通知,工作线程暂停 当所有工作线程都暂停时,主线程读取resultHolder中的数据并更新缓冲区,然后(如果需要)流程从第1点再次开始

我正在尝试实现LZ77的快速版本,我有一个关于并发编程的问题要问你

现在我有一个
final byte[]buffer
和一个
final 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];
    
    final byte[]buffer=新字节[SIZE];
    final MemoryHelper MemoryHelper=新的MemoryHelper();
    最终ArrayBlockingQueue waitBuffer=新ArrayBlockingQueue(TOT_工人);
    最终ArrayBlockingQueue waitResult=新ArrayBlockingQueue(TOT_工人);
    最终整数[]结果文件夹=新整数[大小];
    
    MemoryHelper简单地包装了一个volatile字段,并提供了两种方法:一种用于读取它,另一种用于写入它

    辅助进程的run()代码:

    public void run(){
    试一试{
    //等待主线程
    while(manager.waitBuffer.take()!=关机){
    //加载新的缓冲区值
    manager.memoryHelper.readVolatile();
    //做点什么
    
    对于(int i=a;i您甚至不需要这里的
    volatile
    ,因为已经提供了必要的内存可见性保证:

    内存一致性影响:与其他并发集合一样,在将对象放入另一个线程中的
    BlockingQueue
    之前线程中的操作,在另一个线程中从
    BlockingQueue
    访问或移除该元素之后的操作

    一般来说,如果您已经有了某种类型的同步,您可能不需要做任何特殊的事情来确保内存的可见性,因为您使用的同步原语已经保证了这一点

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

    p.S.


    另外,您似乎可以使用它来代替队列解决方案,它是专为类似场景设计的。

    +1同意。添加了到JLS 17.4.5的链接,该链接描述了与CyclicBarrier尝试的“之前发生”关系,代码更简洁。谢谢!另请参阅
    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();
    }