[concurrency-interest] Canonical example of how to do hand-over-hand locking?
Joe Bowbeer
joe.bowbeer at gmail.com
Fri Apr 27 01:50:34 EDT 2007
On 4/24/07, Aaron Greenhouse <aarong at cs.cmu.edu> wrote:
> The javadoc for the java.util.concurrent.locks package explicitly
> mentions that the locks can be used for hand-over-hand locking. But it
> doesn't give an example. How does this interact with the recommendation
> that unlocks occur in finally clauses so as to insure that all locks are
> always unlocked?
>
In case you're still interested, here's one more example. (I really
like this question:)
The methods are in order of increasing complexity. The 'remove'
method is the most complex, needing nested try-finally's to handle all
the possible exceptions.
public class List {
/**
* Holds one item in a singly-linked list.
* It's convenient here to subclass ReentrantLock
* rather than add one as a field.
*/
private static class Node extends ReentrantLock {
Object item;
Node next;
Node(Object item, Node next) {
this.item = item;
this.next = next;
}
}
/**
* Sentinel node. This node's next field points to
* the first node in the list. Its item field is ignored.
*/
private final Node sentinel = new Node(null, null);
public void addFirst(Object x) {
Node p = sentinel;
p.lock();
try {
p.next = new Node(x, p.next);
} finally {
p.unlock();
}
}
public void addLast(Object x) {
Node p = sentinel;
/* Acquire first lock. */
p.lock();
try {
/* Find tail, using hand-over-hand locking. */
while (p.next != null) {
Node prevp = p;
p.next.lock();
p = p.next;
prevp.unlock();
}
/* Attach new node. */
p.next = new Node(x, null);
} finally {
/* Release final lock that was held. */
p.unlock();
}
}
public boolean contains(Object x) {
Node p = sentinel;
/* Acquire first lock. */
p.lock();
try {
while (p.next != null) {
/*
* Get next lock and release current.
* Sentinel is skipped on first iteration.
*/
Node prevp = p;
p.next.lock();
p = p.next;
prevp.unlock();
/* Found? */
if (x == p.item || x != null && x.equals(p.item))
return true;
}
return false;
} finally {
/* Release final lock that was held. */
p.unlock();
}
}
public boolean remove(Object x) {
Node p = sentinel;
/* Acquire first lock. */
p.lock();
try {
while (p.next != null) {
/*
* Get next lock and release current.
* Sentinel is skipped on first iteration.
*/
Node prevp = p;
p.next.lock();
p = p.next;
try {
/* Found? */
if (x == p.item || x != null && x.equals(p.item)) {
/* Remove node p. */
prevp.next = p.next;
return true;
}
} finally {
prevp.unlock();
}
}
return false;
} finally {
/* Release final lock that was held. */
p.unlock();
}
}
}
--
Joe Bowbeer
More information about the Concurrency-interest
mailing list