@Override
    public boolean offer(final E e) {
        if (null == e) {
            throw new NullPointerException();
        }
        final LinkedQueueAtomicNode<E> nextNode = newNode(e);
        LinkedQueueAtomicNode<E> oldNode = lpProducerNode();
        soProducerNode(nextNode);
        // Should a producer thread get interrupted here the chain WILL be broken until that thread is resumed
        // and completes the store in prev.next. This is a "bubble".
        // Inverting the order here will break the `isEmpty` invariant, and will require matching adjustments elsewhere.
        oldNode.soNext(nextNode);
        return true;
    }
{@inheritDoc} <br>
<p>
IMPLEMENTATION NOTES:<br>
Offer is allowed from a SINGLE thread.<br>
Offer allocates a new node (holding the offered value) and:
<ol>
<li>Sets the new node as the producerNode
<li>Sets that node as the lastProducerNode.next
</ol>
From this follows that producerNode.next is always null and for all other nodes node.next is not null.

@see MessagePassingQueue#offer(Object)
@see java.util.Queue#offer(java.lang.Object)
jctools-core/src/main/java/org/jctools/queues/atomic/SpscLinkedAtomicQueue.java