Если вы можете позволить себе выделять поток только для просмотра вашего сервиса, вот реализация.
Гарантия этого кода в том, что в любое время не может быть более одного активного наблюдателя;и если клиент вызывает onCall
, после этого вызова всегда будет живой наблюдатель.
(в любом случае, обратите внимание, что для простоты кода (во избежание повторения проверок) он все равно будет возможенчтобы клиент вызывал метод onCall () в тот момент, когда истекает срок действия наблюдателя, и наблюдатель мог бы сразу же после этого вызвать очистку. Таким образом, у нас было бы время = 0 между вызовом клиента и операцией очистки.вызов клиента, другой наблюдатель будет спамить)
package stackOverflow;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Service {
private ServiceWatch watch = new ServiceWatch(this::onIdle, 5000L);
public void compute() {
// business here
// and notify the watcher
watch.onCall();
}
private void onIdle() {
// cleanup here, will be executed by the watcher
}
}
class ServiceWatch {
boolean started;
volatile long lastCallTime;
private Runnable onIdle;
private long maxIdle;
private ExecutorService es = Executors.newSingleThreadExecutor();
public ServiceWatch(Runnable onIdle, long maxIdle) {
this.onIdle = onIdle;
this.maxIdle = maxIdle;
}
public synchronized void onCall() {
lastCallTime = System.currentTimeMillis();
if (!started) {
startWatcher();
started = true;
}
}
// spawns a worker-watcher
public void startWatcher() {
es.submit(
new Runnable() {
private void triggerIdle() {
synchronized (ServiceWatch.this) {
onIdle.run();
started = false;
}
}
@Override
public void run() {
long toSleep;
do {
toSleep = getSleepTime();
if (toSleep > 0) {
try {
Thread.sleep(toSleep);
} catch (InterruptedException e) {
triggerIdle();
toSleep = 0;
}
} else {
triggerIdle();
}
} while (toSleep>0);
}
});
}
private long getSleepTime() {
return (lastCallTime + maxIdle) - System.currentTimeMillis();
}
}