首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

构建一个高效可复用缓存程序

一屋不扫何以扫天下?———《后汉书·陈蕃传》它告诉我们,要从一点一滴的小事开始积累,才能做成一番大事业。

PS: 如果觉得本文有用的话,请帮忙点赞,留言评论支持一下哦,您的支持是我最大的动力!谢谢啦~

这几天更新了这么多篇文章,其实这些都是并发编程中最基础的知识。现在,我们是时候利用这些知识来写一个小程序了。本篇文章就来介绍如何构建一个用来存储计算结果的高效、可伸缩高速缓存,虽然简单,但也可以说算是对前面知识的一次运用了。

高速缓存,无论是在服务器端还是在前端程序中都有不同形式的实现。复用缓存里的结果可以大大缩短程序的等待时间,提高吞吐量。说的通俗一点就是利用空间换时间。在本篇文章中,将展示构建缓存程序的过程,并且分析每次优化的过程主要是针对什么问题,直至搭建好我们缓存程序。

缓存相关介绍可以参考我的这篇文章,基本概念了解一下:https://blog.csdn.net/amd123456789/article/details/52092927

下面的例子,我们想构建一个存放计算结果的缓存程序,其中计算的过程是耗时操作。

第一个版本

首先,创建一个接口 Compute,V 表示计算出来结果的类型,A表示输入对象的类型。

其次,创建一个实现类继承这个接口,ExpensiveCompute,用来实现这个计算耗时操作。

然后,创建一个 Compute 接口的包装器,Memorizer,程序的核心类;用于存储计算结果和封装整个缓存的逻辑实现。到时候,如果我们要更改方案,只需要简单修改这个包装器就可以了,其他实现类都不用修改。(装饰器的好处体现在这里)

最后,创建一个控制类 Controller 来模拟缓存的过程。

下面直接看代码,已经详细注释。

(1)Compute 接口。

(2)ExpensiveFunction,计算耗时操作的实现类。

(3)Memorizer,缓存核心类,封装缓存实现机制,存储计算结果。

(4)Controller, 控制类,启动整个程序。

程序的执行结果如下:

从打印的 log 可以看出执行过程了,存储过的结果不会再重复计算,能够正确的把计算结果缓存起来。

但是这样的程序,面对高并发的情况,效率会很低。为什么?

因为 compute 是同步方法,每次只能有一个线程访问,其他线程全部阻塞!假如当前操作非常耗时,那么其他线程将会全部阻塞,程序的吞吐量和响应性将会变得十分糟糕。

面对这样潜在的问题,那么我们可以用一个线程安全的 Map 来替代 HashMap。

第二个版本

Memorizer的实现用 ConcurrentHashMap 来代替 HashMap,同时去掉compute方法同步锁。修改如下:

但是执行结果还是有些小问题:

这里我们可以看到,key1 计算了两次,说明现在的程序还不能保证线程安全。我们来看下面时序图,就明白了为啥程序执行会出错:

那么,怎么样才能避免这种情况发生?这又是一个需要我们思考的问题。有没有办法 B 线程去访问的时候,知道 A 线程已经在计算了,避免重复计算呢?

问题的原因就是这个代码中存在[检查没有则更新]的复合操作。如果想要这个复合操作能够保证同步,那么必须将这个复合代码全部加上锁。然而还有更好的方法,因为并发容器提供了这个同步操作ConcurrentHashMap@putIfAbsent(),保证这个复合操作是同步的。所以省去了手动加锁,直接用这个容器便解决了问题。

另外,我们还想把耗时操作在存进缓存的时候提取出来,不必等待计算出结果,再把结果存进缓存。FutureTask 具备这种功能,它代表一个计算可能在运行中,也可能已经结束。把这个耗时操作封装在 FutureTask 里面,然后直接把 FutureTask 存进缓存。同时,上图 B 线程访问的时候,它可以阻塞 B 线程,直至 A 计算出结果,然后 B 直接拿到 A 计算的结果。

第三个版本

现在知道方案了,这次我们同样修改 Memorizer 类。

按照上面修改后,执行结果已经达到我们的预期:

这便是我们想要构建的高效可复用的缓存程序。但是真正实用的话,远远不止这些。比如,实际运用中如何处理下面这个问题:

1. 缓存过期怎么处理?

这个问题留给我们去思考,当然,如果你想知道怎么处理,可以关注我的微信公众号:[林里少年](id:seaicelin)

回复 [缓存] 获取这个问题的答案源代码。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180608G23P9Y00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券