说明:代码升级详情请见每次commit。
虽经多次升级,但由于水平有限,本项目实属玩具类型缓存。
- 代码实现: 缓存功能粗浅地可以认为由Key查Value,若可以在缓存中查到,直接返回。否则查询数据库,并将结果写入缓存,因此最直接的想法就是用一个HashMap来作为缓存项目最底层的数据结构。并用sychronized保证线程安全(HashMap在多线程环境下进行put操作可能会引起死循环)
- 明显缺陷:虽然最基础的功能是实现了,但是由于使用了synchronized导致查询操作同时刻最多只能有一个线程访问,和缓存的应用场景背道而驰,何不使用ConcurrentHashmap呢?
-
代码改进:使用ConcurrentHashmap初步解决了线程安全问题和性能问题。
-
明显缺陷:重复计算问题。 经过测试发现,当到多个任务到达时间相近时,由于首次计算结果还未得出,导致即使后续有相同的计算任务,而又一次进入执行计算的代码,浪费了服务器资源。
-
代码改进:使用Future机制,用futuretask来存放异步计算的结果
-
明显缺陷:如果后来的任务在第一个任务在futuretask还没有put进缓存时被调度执行,仍会发生重复计算的问题,虽然这个概率已经比上一个没有引入futuretask版本的降低了很多。
- 代码改进:使用原子操作彻底解决重复计算问题
- 明显缺陷:模拟真实场景,如果由于某种原因计算失败,还需要重新计算
- 代码改进:设置50%的概率计算出错,抛出异常并重新计算,注意缓存污染问题,即发生错误要remove掉相应的值
- 明显缺陷:未考虑缓存有效期问题
- 代码改进:利用ScheduledThreadPoolExecutor实现缓存的定期清除
- 使用线程池测试缓存性能
- 使用CountDownLatch模拟压测
- 使用ThreadLocal确认时间的统一性
补充:版本1.0到1.1之间还实现了缓存和业务类(计算)的解耦