很抱歉,我需要介绍一下环境,否则您可能会误解我的问题。
我有一个缓存管理器
Holder类管理下一次访存的访存,同步和调度,因为缓存是为多个并行调用而设计的。通过Web服务获取的数据具有到期日期(在标头中提供),在此日期之后,持有者可以再次获取该数据,并为下一次到期再次进行调度。我有3个类(用于列表,地图和其他类),但是它们都以相同的方式使用。 Holder
通常,这使我可以在足够的时间内并行执行多个数据流之类的操作,例如
Stream.of(1l, 2l, 3l).parallel().map(cache::getPrice).mapToInt(p->p.copy().price).min();
或者在javafx中进行更复杂的绑定,例如,当价格取决于您要购买的商品数量时
holder类包含一个SelfScheduling
SelfScheduling在缓存中使用ScheduledExecutorService来调度其自己的fetch()方法。它从在0毫秒后调度自身开始,如果出错则在10秒后重新调度自身,或者在获取新数据后在到期后重新调度。它可以暂停,恢复,在创建时启动,也可以停止。
这是我要修改的行为。如果代码中的任何地方未使用Holder,我希望自执行器在过期时从缓存中删除Holder。
仅作参考之用,我的缓存管理器由一个Map
这是我的代码的示例
public class CacheExample {
public static class Holder<T>{
SimpleObjectProperty<T> data = new SimpleObjectProperty<>();
// real code removed
T copy() {
return null;
}
Observable asObservable() {
return null;
}
void follow(ChangeListener<? super T> listener) {
}
}
public static class SelfScheduled implements Runnable {
// should use enum
private Object state = "start";
public void schedule(long ms) {
// check state, sync, etc.
}
@Override
public void run() {
long next = fetch();
schedule(next);
}
public long fetch() {
// set the value in the holder
// return the next expiry
return 0;
}
}
public Map<Long, Holder<Object>> cachePrices = new HashMap<>();
public Holder<Object> getPrice(long param) {
Holder<Object> ret = cachePrices.get(param);
if (ret == null) {
// sync, re check, etc.
synchronized (cachePrices) {
ret = cachePrices.get(param);
if (ret == null) {
ret = new Holder<>();
// should be the fetch() call instead of null
makeSchedule(ret.data, null);
}
}
}
return ret;
}
public void makeSchedule(SimpleObjectProperty<Object> data, Runnable run) {
// code removed.
// creates a selfscheduler with fetch method and the data to store the
// result.
}
}
如上所述,我想修改缓存将数据保存在内存中的方式。 特别是,我认为没有理由维护大量的自调度实体以在不再使用这些数据时提取数据。如果到期时间是5s(某些Web服务是ARE),并且我缓存了1000个数据(这是一个非常低的值),那么这意味着我将无缘无故地每秒200 fetch()。
我期望的是,当不再使用Holder时,自调度会自行停止,而不是获取数据,而是将其从缓存中删除。例子:
Holder< Price > p = cache.getPrice(1);
// here if the fetch() is called it should fetch the data
p.copy().price;
// now the price is no more used, on next fetch() it should remove p from the cache.
// If that happens, and later I re enter that code, the holder and the selfscheduler will be re created.
Holder< Price > p2 = cache.getPrice(22);
mylist.add(p2);
// now there is a strong reference to this price, so the fetch() method will keep scheduling the selfscheduler
// until mylist is no more strongly referenced.
但是,我对适当技术的了解仅限于该领域。据我了解,我应该在缓存管理器和自调度中使用一个弱引用,以了解何时不再对持有者进行更强的引用(通常,通过检查引用是否为null来启动fetch(),在这种情况下只需停止);但是,这将导致持有人在下一次到期之前被GC,这是我不希望的:有些数据的到期时间很长,并且只能用于简单的方法,例如cache.getShopLocation()不应被GC在使用copy()返回的值之后。
因此,此代码不正确:
public class CacheExampleIncorrect {
public static class Holder<T>{
SimpleObjectProperty<T> data = new SimpleObjectProperty<>();
// real code removed
T copy() {
return null;
}
Observable asObservable() {
return null;
}
void follow(ChangeListener<? super T> listener) {
}
}
public static class SelfScheduled<T> implements Runnable {
WeakReference<Holder<T>> holder;
Runnable onDelete;
public void schedule(long ms) {
// check state, sync, etc.
}
@Override
public void run() {
Holder<T> h = holder.get();
if (h == null) {
onDelete.run();
return;
}
long next = fetch(h);
schedule(next);
}
public long fetch(Holder<T> h) {
// set the value in the holder
// return the next expiry
return 0;
}
}
public Map<Long, WeakReference<Holder<Object>>> cachePrices = new HashMap<>();
public Holder<Object> getPrice(long param) {
WeakReference<Holder<Object>> h = cachePrices.get(param);
Holder<Object> ret = h == null ? null : h.get();
if (h == null) {
synchronized (cachePrices) {
h = cachePrices.get(param);
ret = h == null ? null : h.get();
if (ret == null) {
ret = new Holder<>();
h = new WeakReference<>(ret);
// should be the fetch() call instead of null
SelfScheduled<Object> sched = makeSchedule(h, null);
cachePrices.put(param, h);
// should be synced on cachedprice
sched.onDelete = () -> cachePrices.remove(param);
}
}
}
return ret;
}
public <T> SelfScheduled<T> makeSchedule(WeakReference<Holder<Object>> h, Runnable run) {
// creates a selfscheduler with fetch method and the data to store the
// result.
return null;
}
}