java建立高效、可伸缩性缓存

缓存
写入前,先排重,同时要防止重复写(两个线程同时写入),或者是重复读(已有线程写入,正在计算,另一个线程可以不必继续访问,直接等待结果就好)。

关键点:
1- ConcurrentHashMap分段锁。
2- Callable启动线程,返回Future对象。

代码:


public interface Computable {

    V compute(K arg)throws InterruptedException;

}


public class Memoizer implements Computable {

    private final Map> cache = new ConcurrentHashMap<>();
    private  Computable c=null;

    public Memoizer(Computable c) { this.c = c; }

    public V compute(final K arg) throws InterruptedException{

        while(true){
            Future f = cache.get(arg);
            if(f==null){
                Callable call = new Callable() {
                    @Override
                    public V call() throws InterruptedException {
                        return c.compute(arg);
                    }
                };
                FutureTask ft = new FutureTask(call);
                f = cache.putIfAbsent(arg,ft);
                if(f==null){
                    f = ft;
                    ft.run();
                }
            }
            try{
                return f.get();
            }catch (CancellationException e){
                cache.remove(arg,f);
            }catch(ExecutionException e){
                e.printStackTrace();
            }
        }

    }
}

分析:
在多线程情况下,建立高效缓存,首先要考虑的是缓存的重复写,和重复读问题。
如何解决重复写
1:利用ConcurrentHashMap解决重复写,相同的key覆盖,同时分段锁segment更加精细,有利于数据的同步。
2:在写入前检查是否已有线程写入cache.get(arg)。
3:没有写入再通过ConcurrentHashMap的cache.putIfAbsent(arg,ft)方法,提供原子性写入(防止两个线程同时写入的情况。)
4:如果写入了,则直接等待正在进行计算,f.get()处于阻塞状态,直到返回结果。

说明
受教与《并发编程实践》

你可能感兴趣的:(java)