package linkedlists.lockbased; import java.util.concurrent.atomic.AtomicLong; public class Node { public final int value; /** next pointer */ public volatile Node next; /** deleted flag */ public volatile boolean isDeleted = false; /** node version + locked flag */ private final AtomicLong lock = new AtomicLong(0); /** Binary value with all bits 1 and last bit 0 : 1111...1110 */ private static final long BIT_MASK = -2; public Node(final int value) { this.value = value; } public Node(final int value, final Node next) { this.value = value; this.next = next; } /** * Get the current version of this node * * @return version number */ public long getVersion() { // this will return the lock value with the last bit set to 0 // i.e. if the value is even it stays the same, odd value becomes the lower even value // e.g. 4 --> 4, 7 --> 6 return lock.get() & BIT_MASK; } /** * Try to lock this node if the version matches * * @param version * expected version * @return true = successfully locked / false = failed because version changed and/or already locked */ public boolean tryLockAtVersion(final long version) { if (lock.get() == version) { return lock.compareAndSet(version, version + 1); } else { return false; } } /** * Unlock the node and increment the version. Should only be called after successfully calling * {@code tryLockAtVersion(version)} */ public void unlockAndIncrementVersion() { lock.incrementAndGet(); } /** * Unlock the node without updating the version. Should only be called after successfully calling * {@code tryLockAtVersion(version)} */ public void unlock() { lock.decrementAndGet(); } /** * Spin-lock */ public void lock() { while (!tryLockAtVersion(getVersion())) { } } public void resetLock() { lock.set(0); } }