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

时间:2017-08-17 07:10:25

标签: java concurrency producer-consumer

我看到它的方式,生产者和消费者线程都可以单独缓存计数并因此做出错误的决定。如果变量不是volatile,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;
        }
  }

3 个答案:

答案 0 :(得分:5)

不,两种方法都使用class AgentLoader { public static void main(String[] args) { String processId = ... File agentJar = ... ByteBuddyAgent.attach(processId, agentJar); } } 关键字定义,这意味着它们永远不会同时执行,并且内存将被同步synchronized块内访问的变量永远不需要volatile

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

  

Memory Consistency Properties

     

"发布之前的行动"同步方法,如Lock.unlock,Semaphore.release和CountDownLatch.countDown发生在成功"获取"之后的动作之前。另一个线程中同一个同步器对象上的Lock.lock,Semaphore.acquire,Condition.await和CountDownLatch.await等方法。

答案 1 :(得分:0)

奥列格说。 synchronized关键字既表示块不能并行执行,也表示存储器将被同步,即写入主存储器。

这意味着在上面的代码中向count变量添加synchronized或volotile不会做任何事情,因为count变量只能在同步的部分中访问。

答案 2 :(得分:0)

根据: -

Synchronized Oracle Docs

  

当同步方法退出时,它会自动建立   与任何后续调用a之前发生的关系   同一对象的同步方法。这保证了变化   所有线程都可以看到对象的状态。

因此,一旦线程放弃锁定,所有缓存都会被刷新并且与主内存同步更改。因此,在上面的代码中,我们不需要为实例变量使用volatile关键字。