All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netty.util.internal.MpscLinkedQueue Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 35.0.0.Beta1
Show newest version
/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
/**
 * Copyright (C) 2009-2013 Typesafe Inc. 
 */
package io.netty.util.internal;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;

/**
 * A lock-free concurrent single-consumer multi-producer {@link Queue}.
 * It allows multiple producer threads to perform the following operations simultaneously:
 * 
    *
  • {@link #offer(Object)}, {@link #add(Object)}, and {@link #addAll(Collection)}
  • *
  • All other read-only operations: *
      *
    • {@link #contains(Object)} and {@link #containsAll(Collection)}
    • *
    • {@link #element()}, {@link #peek()}
    • *
    • {@link #size()} and {@link #isEmpty()}
    • *
    • {@link #iterator()} (except {@link Iterator#remove()}
    • *
    • {@link #toArray()} and {@link #toArray(Object[])}
    • *
    *
  • *
* .. while only one consumer thread is allowed to perform the following operations exclusively: *
    *
  • {@link #poll()} and {@link #remove()}
  • *
  • {@link #remove(Object)}, {@link #removeAll(Collection)}, and {@link #retainAll(Collection)}
  • *
  • {@link #clear()}
  • {@link #} *
* * The behavior of this implementation is undefined if you perform the operations for a consumer thread only * from multiple threads. * * The initial implementation is based on: * * and adopted padded head node changes from: * * data structure modified to avoid false sharing between head and tail Ref as per implementation of MpscLinkedQueue * on JCTools project. */ final class MpscLinkedQueue extends MpscLinkedQueueTailRef implements Queue { private static final long serialVersionUID = -1878402552271506449L; long p00, p01, p02, p03, p04, p05, p06, p07; long p30, p31, p32, p33, p34, p35, p36, p37; // offer() occurs at the tail of the linked list. // poll() occurs at the head of the linked list. // // Resulting layout is: // // head --next--> 1st element --next--> 2nd element --next--> ... tail (last element) // // where the head is a dummy node whose value is null. // // offer() appends a new node next to the tail using AtomicReference.getAndSet() // poll() removes head from the linked list and promotes the 1st element to the head, // setting its value to null if possible. // // Also note that this class extends AtomicReference for the "tail" slot (which is the one that is appended to) // since Unsafe does not expose XCHG operation intrinsically. MpscLinkedQueue() { MpscLinkedQueueNode tombstone = new DefaultNode(null); setHeadRef(tombstone); setTailRef(tombstone); } /** * Returns the node right next to the head, which contains the first element of this queue. */ private MpscLinkedQueueNode peekNode() { MpscLinkedQueueNode head = headRef(); MpscLinkedQueueNode next = head.next(); if (next == null && head != tailRef()) { // if tail != head this is not going to change until consumer makes progress // we can avoid reading the head and just spin on next until it shows up // // See https://github.com/akka/akka/pull/15596 do { next = head.next(); } while (next == null); } return next; } @Override @SuppressWarnings("unchecked") public boolean offer(E value) { if (value == null) { throw new NullPointerException("value"); } final MpscLinkedQueueNode newTail; if (value instanceof MpscLinkedQueueNode) { newTail = (MpscLinkedQueueNode) value; newTail.setNext(null); } else { newTail = new DefaultNode(value); } MpscLinkedQueueNode oldTail = getAndSetTailRef(newTail); oldTail.setNext(newTail); return true; } @Override public E poll() { final MpscLinkedQueueNode next = peekNode(); if (next == null) { return null; } // next becomes a new head. MpscLinkedQueueNode oldHead = headRef(); // Similar to 'headRef.node = next', but slightly faster (storestore vs loadstore) // See: http://robsjava.blogspot.com/2013/06/a-faster-volatile.html // See: http://psy-lob-saw.blogspot.com/2012/12/atomiclazyset-is-performance-win-for.html lazySetHeadRef(next); // Break the linkage between the old head and the new head. oldHead.unlink(); return next.clearMaybe(); } @Override public E peek() { final MpscLinkedQueueNode next = peekNode(); if (next == null) { return null; } return next.value(); } @Override public int size() { int count = 0; MpscLinkedQueueNode n = peekNode(); for (;;) { if (n == null) { break; } count ++; n = n.next(); } return count; } @Override public boolean isEmpty() { return peekNode() == null; } @Override public boolean contains(Object o) { MpscLinkedQueueNode n = peekNode(); for (;;) { if (n == null) { break; } if (n.value() == o) { return true; } n = n.next(); } return false; } @Override public Iterator iterator() { return new Iterator() { private MpscLinkedQueueNode node = peekNode(); @Override public boolean hasNext() { return node != null; } @Override public E next() { MpscLinkedQueueNode node = this.node; if (node == null) { throw new NoSuchElementException(); } E value = node.value(); this.node = node.next(); return value; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public boolean add(E e) { if (offer(e)) { return true; } throw new IllegalStateException("queue full"); } @Override public E remove() { E e = poll(); if (e != null) { return e; } throw new NoSuchElementException(); } @Override public E element() { E e = peek(); if (e != null) { return e; } throw new NoSuchElementException(); } @Override public Object[] toArray() { final Object[] array = new Object[size()]; final Iterator it = iterator(); for (int i = 0; i < array.length; i ++) { if (it.hasNext()) { array[i] = it.next(); } else { return Arrays.copyOf(array, i); } } return array; } @Override @SuppressWarnings("unchecked") public T[] toArray(T[] a) { final int size = size(); final T[] array; if (a.length >= size) { array = a; } else { array = (T[]) Array.newInstance(a.getClass().getComponentType(), size); } final Iterator it = iterator(); for (int i = 0; i < array.length; i++) { if (it.hasNext()) { array[i] = (T) it.next(); } else { if (a == array) { array[i] = null; return array; } if (a.length < i) { return Arrays.copyOf(array, i); } System.arraycopy(array, 0, a, 0, i); if (a.length > i) { a[i] = null; } return a; } } return array; } @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection c) { for (Object e: c) { if (!contains(e)) { return false; } } return true; } @Override public boolean addAll(Collection c) { if (c == null) { throw new NullPointerException("c"); } if (c == this) { throw new IllegalArgumentException("c == this"); } boolean modified = false; for (E e: c) { add(e); modified = true; } return modified; } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } @Override public void clear() { while (poll() != null) { continue; } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); for (E e: this) { out.writeObject(e); } out.writeObject(null); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); final MpscLinkedQueueNode tombstone = new DefaultNode(null); setHeadRef(tombstone); setTailRef(tombstone); for (;;) { @SuppressWarnings("unchecked") E e = (E) in.readObject(); if (e == null) { break; } add(e); } } private static final class DefaultNode extends MpscLinkedQueueNode { private T value; DefaultNode(T value) { this.value = value; } @Override public T value() { return value; } @Override protected T clearMaybe() { T value = this.value; this.value = null; return value; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy