package com.github.kmkt.util.concurrent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* {@link Gate} の {@link ReentrantLock} による実装。
* 状態に応じスレッドの実行がブロック/通過するゲート処理を行う実行制御インタフェース。
* @see Gate
* 利用サンプル
* <pre>
* {@code
* public static void main(String[] args) {
* try {
* AtomicBoolean loopf = new AtomicBoolean(true);
* Gate gate = new LockGate(false);
* Thread loop = new Thread(new Runnable() {
* public void run() {
* System.out.println("Start thread");
* try {
* while (loopf.get()) {
* if (!gate.gate(100, TimeUnit.MILLISECONDS)) { // Gate がブロック状態の場合はブロックする
* System.out.print("t"); // timeout
* continue;
* }
* System.out.print("s");
* Thread.sleep(200);
* }
* } catch (InterruptedException e) {
* e.printStackTrace();
* }
* System.out.println("Exit thread");
* }
* });
* loop.start();
*
* for (int i = 0; i<5;i++) {
* Thread.sleep(1000); // 1sec 走る
* gate.setGateState(true);
* Thread.sleep(2000); // 2sec 停まる
* gate.setGateState(false);
* }
* loopf.set(false);
* } catch (Exception e) {
* e.printStackTrace();
* }
* }
* }
* </pre>
*/
public class LockGate implements Gate {
/** Lock オブジェクト */
private final Lock lock = new ReentrantLock();
/** Lock オブジェクト */
private final Condition condition = lock.newCondition();
/** true await でブロックする false await でブロックしない */
private final AtomicBoolean blockState;
/**
* 非ブロック状態のインスタンスを生成する。
*/
public LockGate() {
this(false);
}
/**
* 初期状態を与えてインスタンスを生成する。
* @param block 初期状態 true ブロック状態 false 非ブロック状態
*/
public LockGate(boolean block) {
this.blockState = new AtomicBoolean(block);
}
/**
* {@inheritDoc}
*/
@Override
public void gate() throws InterruptedException {
if (blockState.get()) {
try {
lock.lock();
while (blockState.get()) {
condition.await();
}
} finally {
lock.unlock();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public long gateNanos(long nanos_timeout) throws InterruptedException {
if (blockState.get()) {
try {
lock.lock();
while (blockState.get()) {
nanos_timeout = condition.awaitNanos(nanos_timeout);
if (nanos_timeout <= 0)
return nanos_timeout;
}
} finally {
lock.unlock();
}
}
return nanos_timeout;
}
/**
* {@inheritDoc}
*/
@Override
public boolean gate(long time, TimeUnit unit) throws InterruptedException {
return gateNanos(unit.toNanos(time)) > 0;
}
/**
* {@inheritDoc}
*/
@Override
public void setGateState(boolean block) {
if (block == true) {
this.blockState.set(true);
} else {
if (!this.blockState.compareAndSet(true, false))
return;
try {
lock.lock();
condition.signalAll();
} finally {
lock.unlock();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean getGateState() {
return this.blockState.get();
}
/**
* {@inheritDoc}
*/
@Override
public void setGate() {
setGateState(true);
}
/**
* {@inheritDoc}
*/
@Override
public void releaseGate() {
setGateState(false);
}
@Override
public String toString() {
return "LockGate [blockState=" + blockState + "]";
}
}