5.6 构建高效且可伸缩的结果缓存

几乎所有的服务器应用程序都会使用某种形式的缓存。重用之前的计算结果能降低延迟,提高吞吐量,但却需要消耗更多的内存。

像许多“重复发明的轮子”一样,缓存看上去都非常简单。然而,简单的缓存可能会将性能瓶颈转变成可伸缩性瓶颈,即使缓存是用于提升单线程的性能。本节我们将开发一个高效且可伸缩的缓存,用于改进一个高计算开销的函数。我们首先从简单的HashMap开始,然后分析它的并发性缺陷,并讨论如何修复它们。

在程序清单5-16的Computable<A, V>接口中声明了一个函数Computable,其输入类型为A,输出类型为V。在ExpensiveFunction中实现的Computable,需要很长的时间来计算结果,我们将创建一个Computable包装器,帮助记住之前的计算结果,并将缓存过程封装起来。(这项技术被称为“记忆[Memoization]”。)

程序清单5-16 使用HashMap和同步机制来初始化缓存

public interface Computable<A, V>{

V compute(A arg)throws InterruptedException;

}

public class ExpensiveFunction

implements Computable<String, BigInteger>{

public BigInteger compute(String arg){

//在经过长时间的计算后

return new BigInteger(arg);

}

}

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

@GuardedBy("this")

private ...

Get Java并发编程实战 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.