





pred Reachable?
curr next?


Runtimes: 1M Operations
| num elements | coarse-grained | fine-grained | optimistic |
|---|---|---|---|
| 10 | 0.11 s | 0.14 s | 0.13 s |
| 100 | 0.14 s | 0.46 s | 0.19 s |
| 1000 | 1.1 s | 3.9 s | 2.2 s |
| 10000 | 28 s | 39 s | 59 s |
Runtimes: 1M Operations
| num elements | coarse-grained | fine-grained | optimistic |
|---|---|---|---|
| 10 | 0.21 s | 0.36 s | 0.33 s |
| 100 | 0.27 s | 1.80 s | 0.38 s |
| 1000 | 1.8 s | 4.7 s | 0.86 s |
| 10,000 | 32 s | 17 s | 9.2 s |
Note: fewer elements $\implies$ greater contention
Under best circumstances:
Under contention:
Operations are complicated because they consist of several steps
Validation simplified:




pred.next == curr?




Node in Code private class Node {
T item;
int key;
Node next;
Lock lock;
volatile boolean marked;
public Node (int key) {
this.item = null;
this.key = key;
this.next = null;
this.lock = new ReentrantLock();
this.marked = false;
}
public Node (T item) {
this.item = item;
this.key = item.hashCode();
this.next = null;
this.lock = new ReentrantLock();
}
public void lock () {
lock.lock();
}
public void unlock () {
lock.unlock();
}
}
private boolean validate (Node pred, Node curr) {
return !pred.marked && !curr.marked && pred.next == curr;
}
contains() no longer acquires locks
public boolean contains (T item) {
int key = item.hashCode();
Node curr = head;
while (curr.key < key) {
curr = curr.next;
}
return curr.key == key && !curr.marked;
}
Runtimes: 1M Operations
| n elts | coarse | fine | optimistic | lazy |
|---|---|---|---|---|
| 10 | 0.11 s | 0.14 s | 0.13 s | 0.11 s |
| 100 | 0.14 s | 0.46 s | 0.19 s | 0.13 s |
| 1000 | 1.1 s | 3.9 s | 2.2 s | 1.1 s |
| 10000 | 28 s | 39 s | 59 s | 29 s |
Runtimes: 1M Operations
| n elts | coarse | fine | optimistic | lazy |
|---|---|---|---|---|
| 10 | 0.21 s | 0.36 s | 0.33 s | 0.33 s |
| 100 | 0.27 s | 1.80 s | 0.38 s | 0.12 s |
| 1000 | 1.8 s | 4.7 s | 0.86 s | 0.19 s |
| 10,000 | 32 s | 17 s | 9.2 s | 4.7 s |
Note: fewer elements $\implies$ greater contention
Advantages:
contains methodDisadvantages:
add and remove still blockingCan we make all of the operations wait-free?
The issue:
Cause for hope:
private boolean validate (Node pred, Node curr) {
return !pred.marked && !curr.marked && pred.next == curr;
}
add) is simple, local:
Node node = new Node(item);
node.next = curr;
pred.next = node; // this is the only step that modifies list!
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 fields
mark indicates logical removalFor add/remove:
remove)compareAndSet to atomically
next field of predecessorFor contains:
Other linear data structures!