Baseline: 58810ms
No others were significantly faster than the baseline.
Baseline: 8034ms
Concurrent Linked Lists, Four Ways:
contains implementation!Nonblocking linked lists!
Question. Can we avoid locks entirely?
Validataion:
private boolean validate (Node pred, Node curr) {
return !pred.marked && !curr.marked && pred.next == curr;
}
Modification (e.g., add):
Node node = new Node(item);
node.next = curr;
pred.next = node; // this is the only step that modifies list!
The issue:
If we can
then maybe we can avoid locking?
Better living with atomics!
AtomicMarkableReference<T>T
marked
boolean compareAndSet(T expectedRef, T newRef, boolean expectedMark, boolean newMark)T get(boolean[] marked)T getReference()boolean isMarked()Use AtomicMarkableReference<Node> for Node references
mark indicates logical removalFor add/remove:
remove)compareAndSet to atomically
next field of predecessorFor contains:
NonblockingList DesignSee NonblockingList.java
Node class, AtomicMarkableReference<Node> next is marked if this Node is logically removed
LazyList
Window class stores two Nodes: prev, curr
NonblockingList method find returns a Window
find also removes any marked nodes encounteredQuestion. Why should methods perform physical removal for other pending operations?
Node curr storing value with predecessor pred
curr for (logical) removal
cur.next to true
pred.next
public boolean remove(T item) {
int key = item.hashCode();
boolean snip;
while (true) {
Window window = find(head, key);
Node pred = window.pred;
Node curr = window.curr;
if (curr.key != key) { return false; }
// curr contains item
...
}
}
public boolean remove(T item) {
...
while (true) {
...
// curr contains item
Node succ = curr.next.getReference();
snip = curr.next.compareAndSet(succ, succ, false, true);
if (!snip) {continue;}
pred.next.compareAndSet(curr, succ, false, false);
return true;
}
}
Question. Why don’t we care about return value of pred.next.compareAndSet?
public boolean remove(T item) {
while (true) {
...
// curr logically removed
pred.next.compareAndSet(curr, succ, false, false);
return true;
}
}