import java.time.Duration;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
public class TimeOutTest {
@Test
public void testTaskOunt001() {
TaskTimerProxy timeTask = new TaskTimerProxy(new DefaultTask(Duration.ofMillis(2000)), Duration.ofMillis(1000));
DefaultTimeOutMonitor monitor = new DefaultTimeOutMonitor();
TaskTimeOutListener listener = timeTask.getTaskTimeOutListener();
monitor.register(listener);
ExecutorService executorService = Executors.newFixedThreadPool(4);
executorService.submit(monitor);
executorService.submit(timeTask);
for (int i = 0; i < 100; i++) {
System.out.println(listener.isTimeOut() + " " + listener.hasEnd());
}
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
interface TaskTimer {
void start();
void setTimeOut(Duration duration);
void end();
boolean isTimeOut();
void reset();
boolean hasEnd();
boolean hasStart();
}
interface TimeOutListener {
public void onTimeOut();
public void onEnd();
}
interface TaskTimeOutListener extends TaskTimer, TimeOutListener {
}
interface TimeOutMonitor {
void register(TaskTimeOutListener listener);
void unregister(TaskTimeOutListener listener);
}
class DefaultTimeOutMonitor implements TimeOutMonitor, Runnable {
ConcurrentLinkedDeque<TaskTimeOutListener> listeners = new ConcurrentLinkedDeque<>();
@Override
public void register(TaskTimeOutListener listener) {
listeners.add(listener);
}
@Override
public void unregister(TaskTimeOutListener listener) {
listeners.remove(listener);
}
@Override
public void run() {
while (true) {
try {
for (TaskTimeOutListener listener : listeners) {
if (listener.hasEnd()) {
listener.onEnd();
listeners.remove(listener);
} else if (listener.isTimeOut()) {
listener.onTimeOut();
listeners.remove(listener);
}
}
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
abstract class AbstractTaskTimer implements TaskTimeOutListener {
protected Long startTime;
protected Long endTime;
protected Duration timeOut;
protected volatile boolean isEnd = false;
public AbstractTaskTimer() {
super();
}
public void setDuration(Duration timeOut) {
this.timeOut = timeOut;
}
public AbstractTaskTimer(Duration timeOut) {
super();
this.timeOut = timeOut;
}
@Override
public void start() {
startTime = System.currentTimeMillis();
}
@Override
public void setTimeOut(Duration timeOut) {
this.timeOut = timeOut;
}
@Override
public void end() {
endTime = System.currentTimeMillis();
System.out.println("end task use time:" + (endTime - startTime));
isEnd = true;
}
public boolean hasEnd() {
return isEnd;
}
@Override
public boolean isTimeOut() {
if (startTime == null)
return false;
return startTime + timeOut.toMillis() < System.currentTimeMillis();
}
@Override
public void reset() {
startTime = System.currentTimeMillis();
}
@Override
public boolean hasStart() {
return startTime == null;
}
}
class DefaultTaskTimer extends AbstractTaskTimer {
public DefaultTaskTimer() {
super();
}
public DefaultTaskTimer(Duration timeOut) {
super(timeOut);
}
@Override
public void onTimeOut() {
System.err.println("timeOut:" + isTimeOut() + " hasEnd:" + hasEnd());
}
@Override
public void onEnd() {
System.err.println("timeOut:" + isTimeOut() + " hasEnd:" + hasEnd() + " use time" + (endTime - startTime));
}
}
class TaskTimerProxy implements Runnable {
Runnable task;
TaskTimeOutListener taskTimer;
public TaskTimerProxy(Runnable task) {
this.task = task;
}
public TaskTimerProxy(Runnable task, Duration timeOut) {
this.task = task;
taskTimer = new DefaultTaskTimer(timeOut);
}
public void setTaskTimer(TaskTimeOutListener taskTimer) {
this.taskTimer = taskTimer;
}
public TaskTimeOutListener getTaskTimeOutListener() {
return this.taskTimer;
}
@Override
public void run() {
if (taskTimer == null) {
throw new Error("task timer not set");
}
taskTimer.start();
task.run();
taskTimer.end();
}
}
class DefaultTask implements Runnable {
private Duration sleepDuration;
DefaultTask(Duration sleepDuration) {
this.sleepDuration = sleepDuration;
}
@Override
public void run() {
try {
Thread.sleep(sleepDuration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}