The enumerator traverses the queue without synchronized access.
There is an internal pointer delimiting what part of the queue
has been synchronized into a consistent state, i.e. safe and
valid, for traversal. An alternate version of this class is
also posted for comparison purposes. It uses a test for null
to indicate the apparent head of the queue with the necessary
synchronization to ensure valid memory states.
------------------------
import java.util.*;
public class Mqueue {
QNode anchor = new QNode();
class QNode {
QNode next = null;
Object item = null;
}
public synchronized void enqueue(Object item) {
anchor.next = new QNode();
anchor = anchor.next;
anchor.item = item;
this.notifyAll();
}
public synchronized Enumeration elements() {
class QTail implements Enumeration {
QNode current = anchor;
QNode last = anchor;
public boolean hasMoreElements() {
return true;
}
public Object nextElement() {
if (current == last) {
synchronized(Mqueue.this) {
while(last == anchor) {
try {Mqueue.this.wait(); }
catch (InterruptedException e) {}
}
last = anchor;
}
}
current = current.next;
return current.item;
}
}
return new QTail();
}
}
------------------------
import java.util.*;
public class Mqueue2 {
QNode anchor;
class QNode {
QNode next = null;
Object item = null;
}
public Mqueue2() {
anchor = new QNode();
}
public synchronized void enqueue(Object item) {
QNode z = new QNode();
synchronized (this) {
z.item = item;
} // memory store barrier
anchor.next = z;
anchor = z;
this.notifyAll();
}
public synchronized Enumeration elements() {
class QTail implements Enumeration {
QNode current = anchor;
public boolean hasMoreElements() {
return true;
}
public Object nextElement() {
if (current.next == null) {
synchronized(Mqueue2.this) {
while(current.next == null) {
try {Mqueue2.this.wait(); }
catch (InterruptedException e) {}
}
}
}
current = current.next;
synchronized(this) { // memory fetch barrier
return current.item;
}
}
}
return new QTail();
}
}
Joe Seigh