通过 #compute 将 WeakReferences 添加到 HashMap - 我可以得到 null 吗?

问题描述 投票:0回答:0

假设我有以下缓存实现,目的是将一些数据(在我的例子中是连接池)与另一个对象的最新状态/版本相关联:

public class Demo<V> {

    private final Map<Integer, VAR<V>> cache = new ConcurrentHashMap<>();

    private final ReferenceQueue<V> refq = new ReferenceQueue<>();

    private final Function<Integer, V> factory;

    public Demo(Function<Integer, V> factory) {
        this.factory = factory;
    }

    public static void main(String[] args) throws Exception {
        Demo<Object> demo = new Demo<>(id -> new Object());

        Object data = demo.getCached(1, 0);
        assert data != null;

        WeakReference<Object> keyReference = new WeakReference<>(data);
        data = null;
        while (keyReference.get() != null) {
            System.gc();
            Thread.sleep(1_000);
        }

    }

    public V getCached(int id, int version) {
        assert version >= 0;
        VAR<V> ref = cache.get(id);
        V storedData = ref == null ? null : ref.get();
        int storedVersion = storedData == null ? -1 : ref.getVersion();

        if (storedData == null) {
            cache.remove(id, ref);
        }

        if (storedVersion >= version) {
            return storedData;
        }

        Supplier<VAR<V>> varFactory = () -> {
            V data = factory.apply(id);
            return new WeakVAR(data, id, version);
        };

        BiFunction<Integer, VAR<V>, VAR<V>> replaceFunction = (key, existing) -> {
            V data = existing == null ? null : existing.get();
            if (data == null) {
                return varFactory.get();
            }
            if (existing.getVersion() >= version) {
                return existing;
            }
            return varFactory.get();
        };

        Supplier<V> vFactory = () -> cache.compute(id, replaceFunction).get();

/*
        V result;
        while ((result = vFactory.get()) == null) {
            // nop
        }
        return result;
*/

        return vFactory.get();
    }


    interface VAR<V> {

        int getVersion();

        int getId();

        V get();

    }

    class WeakVAR extends WeakReference<V>
            implements VAR<V> {

        private final int id;

        private final int version;

        public WeakVAR(V referent, int id, int version) {
            super(referent, refq);
            this.id = id;
            this.version = version;
        }

        @Override
        public int getVersion() {
            return version;
        }

        @Override
        public int getId() {
            return id;
        }
    }

}

问题是:当取消引用从

public V getCached(int id, int version)
返回的
WeakReference
时,
Map#compute
方法是否有可能返回null?如果是这样,克服这个问题的最佳方法是什么?忙循环是一个合适的解决方案吗?

java garbage-collection weak-references
© www.soinside.com 2019 - 2024. All rights reserved.