title: AtomicBoolean not getting updated
body: <p>I'm implementing a standard Producer-Consumer program such that producer stops after producing 200 products. To signal this, producer puts -1 to the BlockingQueue variable, which otherwise always contains positive integers.
  My consumer implementation is as below : </p>
  
  <pre><code>public class Consumer implements Runnable{
  private BlockingQueue&lt;Integer&gt; queue;
  private AtomicBoolean isProducerClosed = new AtomicBoolean(false);
  
  public Consumer(BlockingQueue&lt;Integer&gt; queue) {
      this.queue = queue;
  }
  
  @Override
  public void run() {
  
      try {
          Thread.sleep(50);
  
          while(!isProducerClosed.get()) {
              try {
                  Integer value = queue.take();
  
                  if ((value.intValue() == -1)){
                      System.out.println(Thread.currentThread().getName() + " Encountered -1. Signal to shutdown consumers.");
                      //isProducerClosed.set(true);
                      isProducerClosed.compareAndSet(false, true);
                      break;
                  }
  
                  System.out.println(Thread.currentThread().getName() + " consuming : " + value);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  
  
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Alternate consumer logic (still getting same issue) : </p>
  
  <pre><code>@Override
  public void run() {
  
      while(true) {
          try {
              Thread.sleep(50);
              Integer value = null;
  
              synchronized (this) {
                  if(!isProducerClosed.get()) {
                      value = queue.take();
                      if ((value.intValue() == -1)) {
                          System.out.println(Thread.currentThread().getName() + " Encountered -1. Signal to shutdown consumers.");
                          isProducerClosed.set(true);
                          isProducerClosed = isProducerClosed;
                          System.out.println("Current value of isProducerClosed : " + isProducerClosed.get());
                      }
                  }
              }
  
              if (!isProducerClosed.get()) {
                  System.out.println(Thread.currentThread().getName() + " consuming : " + value);
              } else {
                  break;
              }
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
  
      }
  }
  </code></pre>
  
  <p>While executing this, my consumer threads get stuck on <code>queue.take()</code> as if they are waiting for a product to be available in the queue. One possibility could be : all consumer threads checked the condition <code>isProducerClosed.get()</code> at the same time, entered the while loop, and access <code>queue.take()</code> method. Is this correct assumption? If yes, is there any way to implement this without using low level <code>synchronized</code> keyword?
  I tried the same thing with <code>volatile boolean</code> variable and the result was exactly same. Only after making that variable static, was i able to see all consumers getting terminated after encountering -1 in the queue (as the var is now class-owned).</p>
  
  <p>My calling code : </p>
  
  <pre><code>public class ProducerConsumer {
  
  private BlockingQueue&lt;Integer&gt; sharedQueue = new ArrayBlockingQueue&lt;Integer&gt;(10);
  
  
  public void executeProducerConsumer(int producerCount, int consumerCount){
      ExecutorService executorService = Executors.newFixedThreadPool(3, Executors.defaultThreadFactory());
  
      for(int i = 0; i &lt; producerCount; i++) {
          executorService.submit(new Producer(sharedQueue));      //producer
      }
  
      for(int i = 0; i &lt; consumerCount; i++) {
          executorService.submit(new Consumer(sharedQueue));      //i-th consumer.
      }
  
  
      //initiates clossure of threads after completion, in async manner.
      executorService.shutdown();
  
      //wait till all threads are done.
      try {
          executorService.awaitTermination(1, TimeUnit.HOURS);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  
      System.out.println("The End.");
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Producer code : </p>
  
  <pre><code>public class Producer implements Runnable {
  private BlockingQueue&lt;Integer&gt; queue;
  private volatile int maxNumberOfItemsToProduce = 10;
  
  public Producer(BlockingQueue&lt;Integer&gt; queue) {
      this.queue = queue;
  }
  
  @Override
  public void run() {
      Random random = new Random();
  
      while(true){
  
          if(maxNumberOfItemsToProduce == 0) {
              try {
                  queue.put(-1);
                  System.out.println("Terminating Producer after producing max number of products.");
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              break;
          }
  
          try {
              queue.put(random.nextInt(300));
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
  
  
          maxNumberOfItemsToProduce--;
      }
  
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Screenshot of console:
  <a href="https://i.stack.imgur.com/sJ1sW.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/sJ1sW.png" alt="enter image description here"></a></p>