package com.zy.core.thread.support;
|
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.function.LongSupplier;
|
|
public class RecentStationArrivalTracker {
|
|
static final long DEFAULT_RETAIN_MS = 10_000L;
|
|
private final long retainMs;
|
private final LongSupplier nowSupplier;
|
private final Map<Long, Long> arrivalTimeMap = new ConcurrentHashMap<>();
|
private final AtomicLong lastCleanupAt = new AtomicLong(0L);
|
|
public RecentStationArrivalTracker() {
|
this(DEFAULT_RETAIN_MS, System::currentTimeMillis);
|
}
|
|
public RecentStationArrivalTracker(long retainMs, LongSupplier nowSupplier) {
|
this.retainMs = retainMs <= 0L ? DEFAULT_RETAIN_MS : retainMs;
|
this.nowSupplier = nowSupplier == null ? System::currentTimeMillis : nowSupplier;
|
}
|
|
public void observe(Integer stationId, Integer taskNo, boolean loading) {
|
if (!loading) {
|
return;
|
}
|
record(stationId, taskNo);
|
}
|
|
public void record(Integer stationId, Integer taskNo) {
|
Long key = buildKey(stationId, taskNo);
|
if (key == null) {
|
return;
|
}
|
long now = nowSupplier.getAsLong();
|
arrivalTimeMap.put(key, now);
|
cleanupIfNeeded(now);
|
}
|
|
public boolean hasRecentArrival(Integer stationId, Integer taskNo) {
|
Long key = buildKey(stationId, taskNo);
|
if (key == null) {
|
return false;
|
}
|
long now = nowSupplier.getAsLong();
|
Long arrivalAt = arrivalTimeMap.get(key);
|
if (arrivalAt == null) {
|
cleanupIfNeeded(now);
|
return false;
|
}
|
if (now - arrivalAt > retainMs) {
|
arrivalTimeMap.remove(key, arrivalAt);
|
cleanupIfNeeded(now);
|
return false;
|
}
|
cleanupIfNeeded(now);
|
return true;
|
}
|
|
private void cleanupIfNeeded(long now) {
|
long lastCleanup = lastCleanupAt.get();
|
if (now - lastCleanup < retainMs || !lastCleanupAt.compareAndSet(lastCleanup, now)) {
|
return;
|
}
|
for (Map.Entry<Long, Long> entry : arrivalTimeMap.entrySet()) {
|
if (entry == null || now - entry.getValue() <= retainMs) {
|
continue;
|
}
|
arrivalTimeMap.remove(entry.getKey(), entry.getValue());
|
}
|
}
|
|
private Long buildKey(Integer stationId, Integer taskNo) {
|
if (stationId == null || stationId <= 0 || taskNo == null || taskNo <= 0) {
|
return null;
|
}
|
return (((long) stationId) << 32) | (taskNo.longValue() & 0xffffffffL);
|
}
|
}
|