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!