forked from KNEMC/KLALB
65 lines
1.9 KiB
Java
65 lines
1.9 KiB
Java
package org.kne.concurrent;
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.function.Supplier;
|
|
|
|
/**
|
|
* 惰性计算器:只在输入变化且输出被需要时重算。
|
|
*
|
|
* 使用场景:路由表重算、统计信息聚合、UI 数据更新等
|
|
*
|
|
* @param <T> 输出类型
|
|
*/
|
|
public class LazyEvaluator<T> {
|
|
|
|
private final Supplier<T> recomputeFn; // 重算函数(可能较重)
|
|
private final AtomicBoolean dirty = new AtomicBoolean(true); // true表示需要重算
|
|
private volatile T cachedResult; // 缓存结果(volatile保证可见性)
|
|
|
|
/**
|
|
* @param recomputeFn 当真正需要重算时,调用此函数生成新值
|
|
*/
|
|
public LazyEvaluator(Supplier<T> recomputeFn) {
|
|
this.recomputeFn = recomputeFn;
|
|
}
|
|
|
|
/**
|
|
* 标记输入已变化(每次变化都调用)
|
|
* CAS 保证多线程下只有一个线程真正置脏,避免无谓的竞争
|
|
*/
|
|
public boolean markDirty() {
|
|
return dirty.compareAndSet(false, true);
|
|
}
|
|
|
|
/**
|
|
* 获取当前值(如果 dirty 且被需要,则触发重算)
|
|
* 这个方法由需要输出的地方(如 UI 线程、路由引擎)调用
|
|
*/
|
|
public T get() {
|
|
if (dirty.get()) {
|
|
synchronized (this) {
|
|
// double-check:防止多个线程同时进入重算
|
|
if (dirty.get()) {
|
|
cachedResult = recomputeFn.get();
|
|
dirty.set(false);
|
|
}
|
|
}
|
|
}
|
|
return cachedResult;
|
|
}
|
|
|
|
/**
|
|
* 获取当前缓存的值(不触发重算)
|
|
* 适合那些“如果已经算好就直接用,否则也不强求”的场景
|
|
*/
|
|
public T getCached() {
|
|
return cachedResult;
|
|
}
|
|
|
|
/**
|
|
* 当前是否需要重算
|
|
*/
|
|
public boolean isDirty() {
|
|
return dirty.get();
|
|
}
|
|
} |