IT技术博客大学习 共学习 共进步

学习:一个并发的Cache

福林雨-博客 2010-08-02 22:59:47 浏览 5,962 次
以下是代码片段:
public class Memoizer implements Computable {
    private final ConcurrentMap> cache
        = new ConcurrentHashMap>();
    private final Computable c;

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

    public V compute(final A arg) throws InterruptedException {
        while (true) {
            Future f = cache.get(arg);
            if (f == null) {
                Callable eval = new Callable() {
                    public V call() throws InterruptedException {
                        return c.compute(arg);
                    }
                };
                FutureTask ft = new FutureTask(eval);
                f = cache.putIfAbsent(arg, ft); //先把FutureTask放进去再说
                if (f == null) { f = ft; ft.run(); } //开始计算
            }
            try {
                return f.get();
            } catch (CancellationException e) {
                cache.remove(arg, f);
            } catch (ExecutionException e) {
                throw launderThrowable(e.getCause());
            }
        }
    }
}

这个Cache的设计很有意思, 考虑了很多并发的因素. Cache用简单的Map方式来实现.
1) 使用ConcurrentHashMap来存放计算结果
2) 最有趣的一点, ConcurrentHashMap 里存放的内容是 FutureTask. (为什么? 这相当于放一个Latch)
3) 使用了FutureTask来调度计算, 这样多个线程可以分别进行针对不同的参数的计算
4) 基于FutureTask的特性, 先把FutureTask放进了cache, 再对FutureTask计算
5) 用了一个 while(true) 无限循环…
(为什么? 因为如果发现已经有一个线程中进行相同的计算的话, 就直接等待计算结果. 但是等待过程中, 如果FutureTask被中断了呢? 抓住异常, 再等…)
6) 使用putIfAbsent操作, 避免出现两个线程都进行相同的计算

建议继续学习

  1. 一种常见的并发编程场景的处理 (阅读 23,481)
  2. Rolling cURL: PHP并发最佳实践 (阅读 11,362)
  3. 查看 Apache并发请求数及其TCP连接状态 (阅读 9,922)
  4. 大并发下的高性能编程 – 改进的(用户态)自旋锁 (阅读 8,881)
  5. 大型高并发高负载网站的系统架构分析 (阅读 8,842)
  6. Buffer和cache的区别是什么? (阅读 7,840)
  7. 并发编程系列之一:锁的意义 (阅读 7,382)
  8. 谈冷热数据 (阅读 6,880)
  9. 并发框架Disruptor译文 (阅读 6,601)
  10. Linux操作系统中内存buffer和cache的区别 (阅读 6,340)