@Override
    public int fill(Supplier<E> s, int limit)
    {
        if (null == s)
            throw new IllegalArgumentException("supplier is null");
        if (limit < 0)
            throw new IllegalArgumentException("limit is negative:" + limit);
        if (limit == 0)
            return 0;

        final long mask = this.producerMask;

        long pIndex;
        int claimedSlots;
        Thread blockedConsumer = null;
        long batchLimit = 0;
        final long shiftedBatchSize = 2L * limit;

        while (true)
        {
            pIndex = lvProducerIndex();
            long producerLimit = lvProducerLimit();

            // lower bit is indicative of blocked consumer
            if ((pIndex & 1) == 1)
            {
                // observe the blocked thread for the pIndex
                blockedConsumer = lvBlocked();
                if (blockedConsumer == null)
                    continue;// racing, retry
                if(!casProducerIndex(pIndex, pIndex + 1))
                {
                    blockedConsumer = null;
                    continue;
                }
                // We have observed the blocked thread for the pIndex(lv index, lv thread, cas index).
                // We've claimed pIndex, now we need to wake up consumer and set the element
                batchLimit = pIndex + 1;
                pIndex = pIndex - 1;
                break;
            }
            // pIndex is even (lower bit is 0) -> actual index is (pIndex >> 1), consumer is awake

            // we want 'limit' slots, but will settle for whatever is visible to 'producerLimit'
            batchLimit = Math.min(producerLimit, pIndex + shiftedBatchSize); //  -> producerLimit >= batchLimit

            // Use producer limit to save a read of the more rapidly mutated consumer index.
            // Assumption: queue is usually empty or near empty
            if (pIndex >= producerLimit)
            {
                if (!recalculateProducerLimit(mask, pIndex, producerLimit))
                {
                    return 0;
                }
                batchLimit = Math.min(lvProducerLimit(), pIndex + shiftedBatchSize);
            }

            // Claim the index
            if (casProducerIndex(pIndex, batchLimit))
            {
                break;
            }
        }
        claimedSlots = (int) ((batchLimit - pIndex) / 2);

        final E[] buffer = this.producerBuffer;
        // first element offset might be a wakeup, so peeled from loop
        for (int i = 0; i < claimedSlots; i++)
        {
            long offset = modifiedCalcCircularRefElementOffset(pIndex + 2L * i, mask);
            soRefElement(buffer, offset, s.get());
        }

        if (blockedConsumer != null)
        {
            // no point unblocking an unrelated blocked thread, things have obviously moved on
            if (lvBlocked() == blockedConsumer) {
                LockSupport.unpark(blockedConsumer);
            }
        }

        return claimedSlots;
    }
{@inheritDoc}
<p>
This implementation is correct for single consumer thread use only.
jctools-core/src/main/java/org/jctools/queues/MpscBlockingConsumerArrayQueue.java