code: int drainTo(int[] target, int maxElements) {
  
          // non volatile read  ( which is quicker )
          int readLocation = this.consumerReadLocation;
  
          int i = 0;
  
          // to reduce the number of volatile reads we are going to perform a kind of double check reading on the volatile write location
          int writeLocation = this.writeLocation;
  
          do {
  
              // in the for loop below, we are blocked reading unit another item is written, this is because we are empty ( aka size()=0)
              // inside the for loop, getting the 'writeLocation', this will serve as our read memory barrier.
              if (writeLocation == readLocation) {
  
                  writeLocation = this.writeLocation;
  
  
                  if (writeLocation == readLocation) {
  
                      setReadLocation(readLocation);
                      return i;
                  }
              }
  
  
              // sets the nextReadLocation my moving it on by 1, this may cause it it wrap back to the start.
              readLocation = (readLocation + 1 == capacity) ? 0 : readLocation + 1;
  
              // purposely not volatile as the read memory barrier occurred above when we read 'writeLocation'
              target[i] = data[readLocation];
  
  
          } while (i <= maxElements);
  
          setReadLocation(readLocation);
  
          return maxElements;
      }
docs: Removes at most the given number of available elements from this queue and adds them to the given
  collection.  A failure encountered while attempting to add elements to collection <tt>c</tt> may result
  in elements being in neither, either or both collections when the associated exception is thrown.
  Attempts to drain a queue to itself result in <tt>IllegalArgumentException</tt>. Further, the behavior
  of this operation is undefined if the specified collection is modified while the operation is in
  progress.
  
  @param target      the array to transfer elements into
  @param maxElements the maximum number of elements to transfer
  @return the number of elements transferred
  @throws UnsupportedOperationException if addition of elements is not supported by the specified
  collection
  @throws ClassCastException            if the class of an element of this queue prevents it from being
  added to the specified collection
  @throws NullPointerException          if the specified collection is null
  @throws IllegalArgumentException      if the specified collection is this queue, or some property of an
  element of this queue prevents it from being added to the
  specified collection