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 Node
s: 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;
}
}