Proof of Concept for final project due this Friday.
enq and deq methodsAtomicReference for head, tail, next
compareAndSet to validate & update atomicallyhead/tail proactively
deq/enq
public T deq() throws EmptyException {
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 EmptyException();
}
tail.compareAndSet(last, next);
} else {
T value = next.value;
if (head.compareAndSet(first, next))
return value;
}
}
}
}
How can we implement a bounded queue (with locks)?
Keep track of size!
UnboundedQueue
enq and deq methodsfinal int capacity fieldAtomicInteger size field
enq
deq
size <= capacity
Why should size be atomic?
enqLock
size is less than capacity
size < capacity? (partial method)deqLock
size is greater than 0
size > 0? (partial method)Suppose we don’t want to throw exceptions
Question: How might we implement this behavior?
public void enq (T value) {
enqLock.lock();
try {
Node nd = new Node(value);
while (size.get() == capacity) { }; // wait until not full
tail.next = nd;
tail = nd;
} finally {
enqLock.unlock();
}
}
This is wasteful!
while (size.get() == capacity) { }; // wait until not full
The thread:
size.get() == capacity
What if it takes a while until the queue is not full?
The following would be better:
size.get() == capacity
size.get() < capacity











Lock and Condition InterfacesThe Lock interface defines a curious method:
Condition newCondition() returns a new Condition instance that is bound to this Lock instanceThe Condition interface
void await() causes the current thread to wait until it is signalled or interruptedvoid signal() wakes up one waiting threadvoid signalAll() wakes up all waiting threadsDefine condition for enqLock
notFullConditionWhen enqueuing to a full queue
volatile boolean) for thisnotFullCondition.await()
notFullCondition is satisfiedWhen dequeueing
notFullCondition.signalAll()
(Similar: notEmptyCondition for deq method)
BoundedQueue
public class BoundedQueue<T> implements SimpleQueue<T> {
ReentrantLock enqLock, deqLock;
Condition notEmptyCondition, notFullCondition;
AtomicInteger size;
volatile Node head, tail;
final int capacity;
public BoundedQueue(int capacity) {
this.capacity = capacity;
this.head = new Node(null);
this.tail = this.head;
this.size = new AtomicInteger(0);
this.enqLock = new ReentrantLock();
this.notFullCondition = this.enqLock.newCondition();
this.deqLock = new ReentrantLock();
this.notEmptyCondition = this.deqLock.newCondition();
}
public void enq(T item) { ... }
public T deq() { ... }
class Node { ... }
}
public void enq(T item) {
boolean mustWakeDequeuers = false;
Node nd = new Node(item);
enqLock.lock();
try {
while (size.get() == capacity) {
try {
// System.out.println("Queue full!");
notFullCondition.await();
} catch (InterruptedException e) {
// do nothing
}
}
tail.next = nd;
tail = nd;
if (size.getAndIncrement() == 0) {
mustWakeDequeuers = true;
}
} finally {
enqLock.unlock();
}
if (mustWakeDequeuers) {
deqLock.lock();
try {
notEmptyCondition.signalAll();
} finally {
deqLock.unlock();
}
}
}
public T deq() {
T item;
boolean mustWakeEnqueuers = false;
deqLock.lock();
try {
while (head.next == null) {
try {
// System.out.println("Queue empty!");
notEmptyCondition.await();
} catch(InterruptedException e) {
//do nothing
}
}
item = head.next.item;
head = head.next;
if (size.getAndDecrement() == capacity) {
mustWakeEnqueuers = true;
}
} finally {
deqLock.unlock();
}
if (mustWakeEnqueuers) {
enqLock.lock();
try {
notFullCondition.signalAll();
} finally {
enqLock.unlock();
}
}
return item;
}
What if we want to make a lock-free bounded queue?
size and capacity fields to our LockFreeQueue?Basic operations
void push(T item) add a new item to the top of the stackT pop() remove top item from the stack and return it
EmptyException if stack was empty
push() Step 1: Create Node
push() Step 2: Set next

push() Step 3: Set head

push() Complete
pop()?
pop() Step 1: Store value

pop() Step 2: Update head

pop() Step 3: Return value

With locks:
head, coarse locking is natural choiceWithout locks?
Use linked-list implementation
top as an AtomicReference<Node>
compareAndSet to modify top
top points to item’s Node
public class LockFreeStack<T> implements SimpleStack<T> {
AtomicReference<Node> top = new AtomicReference<Node>(null);
public void push(T item) {...}
public T pop() throws EmptyException {...}
class Node {
public T value;
public AtomicReference<Node> next;
public Node(T value) {
this.value = value;
this.next = new AtomicReference<Node>(null);
}
}
}
push
public void push(T item) {
Node nd = new Node(item);
Node oldTop = top.get();
nd.next.set(oldTop);
while (!top.compareAndSet(oldTop, nd)) {
oldTop = top.get();
nd.next.set(oldTop);
}
}
pop
public T pop() throws EmptyException {
while (true) {
Node oldTop = top.get();
if (oldTop == null) {
throw new EmptyException();
}
Node newTop = oldTop.next.get();
if (top.compareAndSet(oldTop, newTop)) {
return oldTop.value;
}
}
}
Modifying top
push/pop rate limited by top.compareAndSet(...)
… or is it?
Consider several concurrent accesses to a stack:
stk.push(item1)
stk.push(item2)
stk.pop()
stk.push(item4)
stk.pop()
stk.pop()
Trick Question. What is the state of stk after these calls?
Match and exchange!
Cut out the middleperson!
push/pop to stack
push, try to find a pop and give them your valuepop, try to find a push and take their valueNext time: implement an exchange object to facilitate this