Objects.requireNonNull(e2, "The offered value 'e2' must be non-null"); final LinkedQueueNode<E> nextNode = new LinkedQueueNode<>(e1); final LinkedQueueNode<E> nextNextNode = new LinkedQueueNode<>(e2); nextNode.soNext(nextNextNode); prevProducerNode.soNext(nextNode); // StoreStore
public E poll() { LinkedQueueNode<E> nextNode = currConsumerNode.lvNext(); final E nextValue = nextNode.getAndNullValue(); currConsumerNode.soNext(currConsumerNode); CONSUMER_NODE_UPDATER.lazySet(this, nextNode); while ((nextNode = currConsumerNode.lvNext()) == null) { } final E nextValue = nextNode.getAndNullValue(); currConsumerNode.soNext(currConsumerNode); CONSUMER_NODE_UPDATER.lazySet(this, nextNode);
Objects.requireNonNull(e2, "The offered value 'e2' must be non-null"); final LinkedQueueNode<E> nextNode = new LinkedQueueNode<>(e1); final LinkedQueueNode<E> nextNextNode = new LinkedQueueNode<>(e2); nextNode.soNext(nextNextNode); prevProducerNode.soNext(nextNode); // StoreStore
@Override public int size() { // Read consumer first, this is important because if the producer is node is 'older' than the consumer // the consumer may overtake it (consume past it) invalidating the 'snapshot' notion of size. LinkedQueueNode<E> chaserNode = consumerNode; LinkedQueueNode<E> producerNode = this.producerNode; int size = 0; // must chase the nodes all the way to the producer node, but there's no need to count beyond expected head. while (chaserNode != producerNode && // don't go passed producer node chaserNode != null && // stop at last node size < Integer.MAX_VALUE) // stop at max int { LinkedQueueNode<E> next; next = chaserNode.lvNext(); // check if this node has been consumed, if so return what we have if (next == chaserNode) { return size; } chaserNode = next; size++; } return size; }
/** * {@inheritDoc} <br> * <p> * IMPLEMENTATION NOTES:<br> * Offer is allowed from multiple threads.<br> * Offer allocates a new node and: * <ol> * <li>Swaps it atomically with current producer node (only one producer 'wins') * <li>Sets the new node as the node following from the swapped producer node * </ol> * This works because each producer is guaranteed to 'plant' a new node and link the old node. No 2 * producers can get the same producer node as part of XCHG guarantee. * * @see java.util.Queue#offer(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public final boolean offer(final E e) { Objects.requireNonNull(e, "The offered value 'e' must be non-null"); final LinkedQueueNode<E> nextNode = new LinkedQueueNode<>(e); final LinkedQueueNode<E> prevProducerNode = PRODUCER_NODE_UPDATER.getAndSet(this, 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. prevProducerNode.soNext(nextNode); // StoreStore return true; }
@Nullable @Override public E peek() { LinkedQueueNode<E> currConsumerNode = consumerNode; // don't load twice, it's alright LinkedQueueNode<E> nextNode = currConsumerNode.lvNext(); if (nextNode != null) { return nextNode.lpValue(); } else if (currConsumerNode != producerNode) { while ((nextNode = currConsumerNode.lvNext()) == null) { } // got the next node... return nextNode.lpValue(); } return null; }
LinkedQueueNode(@Nullable E val) { spValue(val); }
public MpscLinkedQueue() { LinkedQueueNode<E> node = new LinkedQueueNode<>(); CONSUMER_NODE_UPDATER.lazySet(this, node); PRODUCER_NODE_UPDATER.getAndSet(this, node);// this ensures correct construction: // StoreLoad }
public E poll() { LinkedQueueNode<E> nextNode = currConsumerNode.lvNext(); final E nextValue = nextNode.getAndNullValue(); currConsumerNode.soNext(currConsumerNode); CONSUMER_NODE_UPDATER.lazySet(this, nextNode); while ((nextNode = currConsumerNode.lvNext()) == null) { } final E nextValue = nextNode.getAndNullValue(); currConsumerNode.soNext(currConsumerNode); CONSUMER_NODE_UPDATER.lazySet(this, nextNode);
/** * {@inheritDoc} <br> * <p> * IMPLEMENTATION NOTES:<br> * Offer is allowed from multiple threads.<br> * Offer allocates a new node and: * <ol> * <li>Swaps it atomically with current producer node (only one producer 'wins') * <li>Sets the new node as the node following from the swapped producer node * </ol> * This works because each producer is guaranteed to 'plant' a new node and link the old node. No 2 * producers can get the same producer node as part of XCHG guarantee. * * @see java.util.Queue#offer(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public final boolean offer(final E e) { Objects.requireNonNull(e, "The offered value 'e' must be non-null"); final LinkedQueueNode<E> nextNode = new LinkedQueueNode<>(e); final LinkedQueueNode<E> prevProducerNode = PRODUCER_NODE_UPDATER.getAndSet(this, 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. prevProducerNode.soNext(nextNode); // StoreStore return true; }
@Override public int size() { // Read consumer first, this is important because if the producer is node is 'older' than the consumer // the consumer may overtake it (consume past it) invalidating the 'snapshot' notion of size. LinkedQueueNode<E> chaserNode = consumerNode; LinkedQueueNode<E> producerNode = this.producerNode; int size = 0; // must chase the nodes all the way to the producer node, but there's no need to count beyond expected head. while (chaserNode != producerNode && // don't go passed producer node chaserNode != null && // stop at last node size < Integer.MAX_VALUE) // stop at max int { LinkedQueueNode<E> next; next = chaserNode.lvNext(); // check if this node has been consumed, if so return what we have if (next == chaserNode) { return size; } chaserNode = next; size++; } return size; }
@Nullable @Override public E peek() { LinkedQueueNode<E> currConsumerNode = consumerNode; // don't load twice, it's alright LinkedQueueNode<E> nextNode = currConsumerNode.lvNext(); if (nextNode != null) { return nextNode.lpValue(); } else if (currConsumerNode != producerNode) { while ((nextNode = currConsumerNode.lvNext()) == null) { } // got the next node... return nextNode.lpValue(); } return null; }
LinkedQueueNode(@Nullable E val) { spValue(val); }
public MpscLinkedQueue() { LinkedQueueNode<E> node = new LinkedQueueNode<>(); CONSUMER_NODE_UPDATER.lazySet(this, node); PRODUCER_NODE_UPDATER.getAndSet(this, node);// this ensures correct construction: // StoreLoad }