package edu.washington.escience.myria.util.concurrent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* A simple implementation of a reentrant spin lock. A spin lock may have better performance than blocking locks if the
* lock holding code block is very small.
* */
public class ReentrantSpinLock implements Lock {
/**
* Record the thread which currently holds the lock.
* */
private final AtomicReference<Thread> spinLock = new AtomicReference<Thread>();
/**
* Number of hold count.
* */
private int numHoldCount = 0;
/**
* Do the spin lock.
* */
@Override
public final void lock() {
Thread currentT = Thread.currentThread();
if (spinLock.get() != currentT) {
while (!spinLock.compareAndSet(null, currentT)) {
if (currentT.isInterrupted()) {
return;
}
}
}
numHoldCount++;
}
/**
* Unlock this lock.
* */
@Override
public final void unlock() {
Thread currentThread = Thread.currentThread();
if (spinLock.get() != currentThread) {
throw new IllegalStateException(
"The current thread " + currentThread + " does not hold the lock.");
}
numHoldCount--;
if (numHoldCount <= 0) {
spinLock.set(null);
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
Thread currentT = Thread.currentThread();
while (!this.tryLock()) {
if (currentT.isInterrupted()) {
throw new InterruptedException();
}
}
}
@Override
public boolean tryLock() {
Thread currentT = Thread.currentThread();
if (spinLock.get() != currentT) {
if (spinLock.compareAndSet(null, currentT)) {
numHoldCount++;
return true;
}
} else {
numHoldCount++;
return true;
}
return false;
}
@Override
public boolean tryLock(final long time, final TimeUnit unit) throws InterruptedException {
long start = System.nanoTime();
long waitMaxNano = unit.toNanos(time);
Thread currentT = Thread.currentThread();
while (System.nanoTime() - start < waitMaxNano && !this.tryLock()) {
if (currentT.isInterrupted()) {
throw new InterruptedException();
}
}
return isHoldingLock();
}
@Override
public Condition newCondition() {
// TODO Auto-generated method stub
return null;
}
/**
* @return check if current thread is holding the lock.
* */
public boolean isHoldingLock() {
return spinLock.get() == Thread.currentThread();
}
}