java - 为什么下面的生产者消费者代码不需要volatile变量?

标签 java concurrency producer-consumer

在我看来,生产者线程和消费者线程都可以分别缓存计数并因此做出错误的决定。如果变量不是易变的,count++ 可能只是更新缓存吧?

class Buffer {
        private char [] buffer;
        private int count = 0, in = 0, out = 0;

        Buffer(int size)
        {
             buffer = new char[size];
        }

        public synchronized void Put(char c) {
             while(count == buffer.length) 
             {
                  try { wait(); }
                  catch (InterruptedException e) { } 
                  finally { } 
             } 
             System.out.println("Producing " + c + " ...");
             buffer[in] = c; 
             in = (in + 1) % buffer.length; 
             count++; 
             notify(); 
        }

        public synchronized char Get() {
             while (count == 0) 
             {
                  try { wait(); }
                  catch (InterruptedException e) { } 
                  finally { } 
             } 
             char c = buffer[out]; 
             out = (out + 1) % buffer.length;
             count--;
             System.out.println("Consuming " + c + " ..."); 
             notify(); 
             return c;
        }
  }

最佳答案

不,这两个方法都是用synchronized关键字定义的,这意味着它们永远不会同时执行,而且内存将被同步。在 synchronized block 中访问的变量永远不需要 volatile

如果我们使用 Java 提供的其他同步机制,例如 ReentrantReadWriteLock 而不是 synchronized 我们也不需要 volatile,因为正确使用的锁具有相同的内存保证(使用官方语言发生前关系)。

Memory Consistency Properties

Actions prior to "releasing" synchronizer methods such as Lock.unlock, Semaphore.release, and CountDownLatch.countDown happen-before actions subsequent to a successful "acquiring" method such as Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await on the same synchronizer object in another thread.

关于java - 为什么下面的生产者消费者代码不需要volatile变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45728684/

相关文章:

c++ - boost.future : are these two pieces of code equivalent?

java - 为什么不是所有 `Executors` 工厂方法都包装在 `FinalizableDelegatedExecutorService` 中?

java - java线程生产者-消费者

c - 具有信号量和 fork 的产品消费者

java - 使用多线程的生产者消费者程序

java.lang.RuntimeException : Failure delivering result ResultInfo{. ..} 到 Activity {....FacebookSignUp} : java. lang.NullPointerException:

java - 如何使用 jooq 在普通 sql 中使用命名参数

c# - C#中并发安全自定义数据类型的实现

java - 如何在 Spring 的单个事务中使用多个数据源(一个用于读取,另一个用于写入)?

java - Java中Math.exp函数的限制