并发编程实践第5章。使用同步工具类做一个高效且可伸缩的结果缓存

1:使用同步工具类做一个高效且可伸缩的结果缓存

       做缓存一般使用Map结构,当想要取一个键的值时,判断是否存在。如果存在,直接取出即可,如果不存在,则为键计算一个值,将键值对添加到map中。

      现在假设我们要将一个字符串转换成整数,整数加1作为返回值,字符串作为键,返回的整数值作为值。构建一个缓存d。

    1.1首先创建一个转换接口

  

package chapter05.class6;

/**
 * 定义一个参数转换接口
 * @param <K>  被转换参数
 * @param <V>  转换参数
 */
public interface Computable<V,K> {
    V compute(K arg) throws InterruptedException;
}

1.2:创建一个缓存对象

       

package chapter05.class6;

import java.util.concurrent.*;

/**
 * 缓存
 */
public class Memoizer<V,K> implements Computable<V,K> {

    //Future<V>相当于一个能够调用将来结果的容器,结果计算过程交由其它完成。携带结果的任务有Future.
    private final ConcurrentMap<K, Future<V>> cache = new ConcurrentHashMap<>();//使用ConcurrentMap作为缓存。
    private final Computable<V,K> c;  //转换接口
    public Memoizer(Computable<V, K> c) {
        this.c = c;
    }

    @Override
    public V compute(K arg) throws InterruptedException {
        while (true) {
            Future<V> future = cache.get(arg);  //得到一个Future<V>,Future<V>如果不为空,则包含要查找的值

            if (future == null) {  //如果future为空。也就是缓存中没有。
                Callable<V> eval=()->{   //创建一个Callable,调用接口中的计算方法compute,
                    return c.compute(arg); //有可能涉及长时间计算
}; FutureTask<V> futureTask = new FutureTask<V>(eval); //将callable传递给futureTask; future = cache.putIfAbsent(arg, futureTask); //判断arg是否在cache中存在,如果不存在,把计算任务委托给futureTask。这时futureTask还不执行,需要调用下面的run()之后才执行。 // 不过如果有新的线程进入调用取arg的值时,就不能添加了,因为arg已经存在了,只是值还不存在,要等到下面计算完成后,取出结果就行了。 if (future == null) { //如果future为空。 future=futureTask; // 将futureTask赋给future futureTask.run(); //调用eval 中的call方法,相当于调用compute  } } try { return future.get(); //最后通过future.get()得到想要的值V } catch (Exception e) { } } } }

3:编写测试类

package chapter05.class6;

public class MemoizerTest {

    public static void main(String[] args){
        Memoizer memoizer = new Memoizer<Integer,String>((s)->{  //compute方法,被c.compute(arg);调用
            return Integer.parseInt(s)+1;
        });

        try {
            Integer compute = (Integer) memoizer.compute("23");
            System.out.println(compute);  //24
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

posted @ 2018-04-04 10:53  1367356  阅读(179)  评论(0编辑  收藏  举报