import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicReference;
public class LockFreeQueue<T> implements MyQueue<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);
}
public void enq(T item) {
if (item == null) throw new NullPointerException();
Node node = new Node(item);
while (true) {
Node last = tail.get();
Node next = last.next.get();
if (last == tail.get()) {
AtomicReference[] target = {last.next, tail};
Object[] expect = {next, last};
Object[] update = {node, node};
if (multiCompareAndSet(
(AtomicReference<T>[]) target,
(T[]) expect,
(T[]) update)){
return;
}
}
}
}
public T deq() throws NoSuchElementException {
while (true) {
Node first = head.get();
Node last = tail.get();
Node next = first.next.get();
if (first == head.get()) {
if (first == last) {
if (next == null) {
throw new NoSuchElementException();
}
tail.compareAndSet(last, next);
} else {
T value = next.value;
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) {
if (target[0].compareAndSet(expect[0], update[0])) {
if (target[1].compareAndSet(expect[1], update[1])) {
return true;
} else {
target[0].compareAndSet(update[0], expect[0]);
//System.out.println("Bad?");
return false;
}
} else {
//System.out.println("Failed.");
return false;
}
}
public static void main(String [] args) {
int runs = 10;
int numThreads = 6;
int numIterations = 120000;
double runtimes[] = new double[runs];
//If command line argument present, gives patience in seconds.
if (args.length > 0) {
try {
runs = Integer.parseInt(args[0].trim());
numThreads = Integer.parseInt(args[1].trim());
numIterations = Integer.parseInt(args[2].trim());
System.out.format("Runs = %d, NumThreads = %d, NumIterations = %d\n", runs, numThreads, numIterations);
} catch (NumberFormatException e) {
System.err.println("Argument must be an integer.");
System.exit(1);
}
}
for (int i = 0; i < runs; ++i) {
MyQueue<Integer> que = new LockFreeQueue<Integer>();
QueueTester tester = new QueueTester(que);
runtimes[i] = tester.runTest(numThreads, numIterations);
//System.out.println("Run time (" + (i + 1) + "): " + runtimes[i] + "s");
}
double totalRuntime = 0;
for (int i = 0; i < runs; ++i) {
totalRuntime += runtimes[i];
}
System.out.println("Average runtime of " + runs + " runs: " + (totalRuntime / runs) + "s");
}
}