为什么Java对象被缓存?

时间:2010-09-14 10:44:02

标签: java caching

为什么我们需要缓存Java对象?任何人都可以给我一个需要缓存对象的真实世界示例吗?另外,在多线程执行期间,给出一些关于缓存设计和缓存类型以及缓存结果的观点。在Java中支持缓存的所有API是什么?

为什么我需要单独的缓存API,因为我可以在内存中使用普通的java对象。

2 个答案:

答案 0 :(得分:6)

您不需要 来缓存对象,但是您可能希望这样做以节省内存,I / O和CPU资源等。

内存

例如,JVM可能会缓存Integer个对象,每当您要求创建新对象时,它可能只返回对具有相同值的现有对象的引用。阅读Flyweight模式的更多信息。

CPU

通过在缓存中存储需要大量CPU计算的结果,可以节省CPU资源。相关技术:Memoization

I / O

通过在应用程序中缓存一些数据,您可以节省I / O,而不是在每次访问时都访问数据库,硬盘驱动器或网络。

请求的示例:

假设您正在构建一个需要显示股票报价的网站,您将通过Web API (网络I / O)阅读它们。您只需要每分钟更新一次(不经常更改)的价格。许多用户一次使用您的网站(并发/多线程)

缓存解决方案可以是每分钟读取一次股票价格,然后将其保存在线程安全的对象中。每个线程(代表来自并发用户的请求)将从该对象读取,而不是每次都访问Web API(网络I / O节省)

该对象是线程安全的,因此线程在每分钟更新时都不会以不一致的状态读取缓存的值。

  

所以每个客户都需要等待   为其他客户完成他们的   任务?

旁注:这是一个并发问题,而不是缓存问题。

不,不一定,因为线程安全结构不会阻止读取。在此示例中,只有一个线程更新对象(定期一分钟价格更新)。

详细说明,我们会将这些股票价格缓存在ConcurrentHashMap<String, BigDecimal>中,其中字符串代表股票代码,“GOOG”,“ORCL”,“MSFT”等,以及BigDecimal代表股票的价格/报价。

要为您的用户提供服务,您将从该地图中读取值,如下所示:

price = quotesMap.get("GOOG"); // get Google stocks quote

ConcurrentHashMap.get()调用是一个线程安全的非阻塞(不需要锁定)调用,并且您的多个线程可以同时从映射中进行检索。

所有get()调用都将收到最新的已完成更新(由您的价格更新线程调用ConcurrentHashMap.put()以更新价格时)确保安全高速缓冲存储器)。

答案 1 :(得分:4)

您希望在创建它们的行为非常昂贵时缓存对象,这对于从硬件级别的磁盘与ram一直读取数据一直到Java等高级编程语言都是如此。如果创建一个对象需要10ms,而从缓存中提取该对象需要1ms,只要您重新使用这些对象,您可以使用10ms + 1ms来创建对象并重新使用它,或者10ms + 10ms来创建对象两次。您拥有的重用次数越多,缓存效果就越好。

当您编写多线程程序时,您需要考虑对对象的并发访问,如果您有银行帐户对象,并且两个线程读取余额并更新它,您最终可能会看到两个线程都读取相同的价值,并根据该值编写一个新值,因此两个100英镑的存款可能导致您的银行余额仅增加100英镑,因为更新的第二个线程具有当前余额的陈旧价值。

java.util.concurrent包中有很多类来处理并发性以及synchronized关键字。 Oracle here提供了大量资源。