1. 程式人生 > >緩存實現思路

緩存實現思路

線程不安全 時間計算 rri 實現思路 復雜 all 安全 syn 其他

緩存主要為了解決各個組件之間讀取速度不匹配問題,比如寄存器是L1的緩存,L1是L2的緩存,L2是L3的緩存,L3是內存的緩存等。通過讀Java Concurrency Practice P85,實現了一個簡單可以添加和獲取數據的緩存。其它的諸如緩存過期,更新緩存等沒有實現- -!!

代碼

計算接口,用到了裝飾者模式。


public interface Computable<A,V> {
    V compute(A arg);
}

一種計算的實現

public class ExpensiveFunction implements Computable<String,BigInteger> {

    @Override
    public BigInteger compute(String arg) {
       // 經過長時間計算後
        try {
            Thread.sleep(500000);           
        } catch (InterruptedException ie) {

        }
        return new BigInteger(arg); 
    }

}

版本1

通過HashMap時間復雜度為O(1)的特性以及synchronized保證線程安全來構建緩存


public class MyCacheV1<A,V> implements Computable<A,V>{

    private Map<A,V> cache = new HashMap<>();
    private Computable computable;

    public MyCacheV1(Computable computable) {
        this.computable = computable;
    }

    @Override
    public synchronized V compute(A arg) {
        V result = cache.get(arg);
        if (result == null) {
            result = (V)computable.compute(arg);
            cache.put(arg,result);
        }
        return result;
    }

}

版本2

版本1添加了synchronized,多線程情況下造成性能下降 -> 換成ConcurrentHashMap

public class MyCacheV2<A,V> implements Computable<A,V>{

    private Map<A,V> cache = new ConcurrentHashMap<>();
    private Computable computable;

    public MyCacheV2(Computable computable) {
        this.computable = computable;
    }

    @Override
    public V compute(A arg) {
        V result = cache.get(arg);
        if (result == null) {
            result = (V)computable.compute(arg);
            cache.put(arg,result);
        }
        return result;
    }

}

版本3

版本2先判斷 -> 在計算屬於復合操作而且沒有加鎖導致線程不安全會產生重讀計算。如果遇到計算時間非常長的計算,一旦重復會消耗大量的資源。
解決思路:如果其他線程正在計算目標值,當前線程阻塞直到其它線程計算出結果返回即可。
實現:通過FutureTask的get()方法。如果沒有結果,會阻塞當前線程。

public class MyCacheV3<A,V> implements Computable<A,V>{

    private Map<A,FutureTask> cache = new ConcurrentHashMap<>();
    private Computable computable;

    public MyCacheV3(Computable computable) {
        this.computable = computable;
    }

    @Override
    public V compute(A arg) {
        Future future = cache.get(arg);
        if (future == null) {
            FutureTask futureTask = new FutureTask(new Callable() {
                @Override
                public V call() throws Exception {
                    return (V)computable.compute(arg);
                }
            });
            // 用到了ConcurrentHashMap的原子操作
            future = cache.putIfAbsent(arg,futureTask);
            // 二次判斷
            if (future == null) {future = futureTask; futureTask.run();}
        }
        V result = null;
        try {
            result = (V) future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return result;
    }

}

緩存實現思路