/* * LockFreeQueue.java * * Created on December 29, 2005, 2:05 PM * * The Art of Multiprocessor Programming, by Maurice Herlihy and Nir Shavit. * by Maurice Herlihy and Nir Shavit. * Copyright 20065 Elsevier Inc. All rights reserved. */ package queue; import java.util.concurrent.atomic.AtomicReference; /** * Lock-free queue. * Based on Michael and Scott http://doi.acm.org/10.1145/248052.248106 * @param T item type * @author Maurice Herlihy */ public class LockFreeQueue<T> { private AtomicReference<Node> head; private AtomicReference<Node> tail; public LockFreeQueue() { Node sentinel = new Node(null); this.head = new AtomicReference<Node>(sentinel); this.tail = new AtomicReference<Node>(sentinel); } /** * Append item to end of queue. * @param item */ public void enq(T item) { if (item == null) throw new NullPointerException(); Node node = new Node(item); // allocate & initialize new node while (true) { // keep trying Node last = tail.get(); // read tail Node next = last.next.get(); // read next if (last == tail.get()) { // are they consistent? AtomicReference[] target = {last.next, tail}; Object[] expect = {next, last}; Object[] update = {node, node}; if (multiCompareAndSet( (AtomicReference<T>[]) target, (T[]) expect, (T[]) update)){ return; } } } } /** * Remove and return head of queue. * @return remove first item in queue * @throws queue.EmptyException */ public T deq() throws EmptyException { while (true) { Node first = head.get(); Node last = tail.get(); Node next = first.next.get(); if (first == head.get()) {// are they consistent? if (first == last) { // is queue empty or tail falling behind? if (next == null) { // is queue empty? throw new EmptyException(); } // tail is behind, try to advance tail.compareAndSet(last, next); } else { T value = next.value; // read value before dequeuing if (head.compareAndSet(first, next)) return value; } } } } public class Node { public T value; public AtomicReference<Node> next; public Node(T value) { this.value = value; this.next = new AtomicReference<Node>(null); } } private static <T> boolean multiCompareAndSet( AtomicReference<T>[] target, T[] expect, T[] update) { return true; } }