/*
* ----------------------------------------------------
* 使用LockSupport来实现可重入的信号(前面实现的都不是可重入的)
* 除了共享数据本身的原子性、一致性、隔离性的考虑之外
* 作为某种锁的存在的对象常还要考虑中断和重入
* 中断的情况最开始的测试代码中有提到,需要根据具体的情况来考虑如何处理。
* 而重入则是重复对某个带锁方法的调用,有的时候是有意的,有时则是误调用,都需要引起注意。
* ----------------------------------------------------
*/
class ReentrantSema implements IMySemaphore {
private AtomicInteger _iSignal;
private final int _iPermits;
private Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread> ();
// 对于并发线程重入次数需要记录
private ConcurrentHashMap<Thread, Integer> runningThread = new ConcurrentHashMap<Thread, Integer> ();
ReentrantSema(final int i) {
_iSignal = new AtomicInteger(0);
_iPermits = i;
}
public void acquire() throws InterruptedException {
Thread current = Thread.currentThread();
// 判断是否已得到信号量
Integer cnt = runningThread.get(current);
if (cnt != null) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
runningThread.put(current, new Integer(cnt + 1));
return;
}
boolean wasInterrupted = false;
waiters.add(current);
int i, update;
while (true) {
i = _iSignal.get();
if (waiters.peek() != current || (!wasInterrupted && (i >= _iPermits))) {
// 申请条件不够
LockSupport.park(this);
if (Thread.interrupted()) {
wasInterrupted = true;
continue;
}
}
if (wasInterrupted) {
break;
}
if (i >= _iPermits) {
continue;
}
// 利用 AtomicInteger 的 CAS 操作确保申请到信号量
update = i + 1;
if (waiters.peek() == current && _iSignal.compareAndSet(i, update)) {
// get the lock
runningThread.put(current, new Integer(1));
break;
}
}
// 唤醒下一个等待线程
waiters.remove();
LockSupport.unpark(waiters.peek());
if (wasInterrupted) {
throw new InterruptedException();
}
}
public void release() {
Thread current = Thread.currentThread();
Integer cnt = runningThread.get(current);
assert (cnt != null);
// 释放信号时要注意可能只是从某个层次退出
// 完全退出后才能真正释放
if (cnt == 1) {
runningThread.remove(current);
_iSignal.decrementAndGet();
LockSupport.unpark(waiters.peek());
} else {
runningThread.put(current, new Integer(cnt - 1));
}
}
} // END: ReentrantSema
/**
* 带重入方法的 Worker, 会多次调用 acquire 方法
*/
class ReentrantWorker implements Runnable {
private final int _id;
private final long _wait;
private final IMySemaphore _semaphore;
private final long _lCreateTime;
private static void println(final String msg) {
System.out.println(msg);
}
ReentrantWorker(final int id, final IMySemaphore semaphore, final long now) {
_id = id;
_wait = (10 - _id) * 1000;
_semaphore = semaphore;
_lCreateTime = now;
}
public void run() {
try {
// 第一次申请
_semaphore.acquire();
try {
println(String.format("Worker[%d] is running...", _id));
// 重入,子类中很可能会误调用某个已经申请了信号量的方法
// 如果信号量不支持重入,就可能引起死锁
reentrant();
long period = (System.currentTimeMillis() - _lCreateTime) / 1000;
println(String.format("Worker[%d] is end, %d seconds after created.", _id, period));
} catch (InterruptedException ie) {
// swap exception to somewhere
// report and stop this thread
} finally {
// 释放
_semaphore.release();
}
} catch (InterruptedException ie) {
// 申请时被中断
long period = (System.currentTimeMillis() - _lCreateTime) / 1000;
println(String.format("Worker[%d] is interrupted, %d seconds after created.", _id, period));
return;
}
}
private void reentrant() throws InterruptedException {
try {
// 申请
_semaphore.acquire();
try {
long begin = System.currentTimeMillis();
println(String.format("Worker[%d] reentrant success...", _id));
// 又重入一次
reentrant2();
long period = (System.currentTimeMillis() - begin) / 1000;
println(String.format("Worker[%d] reentrant end, %d seconds after created.", _id, period));
} catch (InterruptedException ie) {
throw ie;
} finally {
// 释放
_semaphore.release();
}
} catch (InterruptedException ie) {
// 申请被中断
throw ie;
}
}
private void reentrant2() throws InterruptedException {
try {
// 申请
_semaphore.acquire();
try {
long begin = System.currentTimeMillis();
println(String.format("Worker[%d] reentrant 2 success...", _id));
Thread.currentThread().sleep(_wait);
long period = (System.currentTimeMillis() - begin) / 1000;
println(String.format("Worker[%d] reentrant 2 end, %d seconds after created.", _id, period));
} catch (InterruptedException ie) {
throw ie;
} finally {
// 释放
_semaphore.release();
}
} catch (InterruptedException ie) {
// 申请被中断
throw ie;
}
}
} // END: ReentrantWorker
还有更多的方法可以继续体验……