您当前的位置: 首页 >  Java

顧棟

暂无认证

  • 0浏览

    0关注

    227博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

JAVA缓存- JSR107 最终规范

顧棟 发布时间:2022-03-02 18:05:44 ,浏览量:0

文章目录
  • JSR107 java 缓存规范
    • 什么是缓存
    • 目标
    • Java 缓存 API 未解决
    • 基础知识
      • 核心概念
      • Map与Cache的异同点
      • 一致性
        • 默认一致性
        • 更多一致性模型
      • 缓存拓扑
      • 执行上下文
      • 可重入
    • 简单示例

JSR107 java 缓存规范

原文地址:https://download.oracle.com/otndocs/jcp/jcache-1_0-fr-eval-spec/index.html

PDF下载:JSR107 最终规范

更详细的中文翻译:https://www.codercto.com/a/103936.html java语言规范和java虚拟机规范文档地址(Oracle的):https://docs.oracle.com/javase/specs/index.html java规范提案列表 http://jcp.org/en/jsr/all

本规范描述了 Java 缓存应用程序编程接口(“API”)的目标和功能。

Java Caching API 为 Java 程序从缓存中创建、访问、更新和删除条目提供了一种通用方法。

什么是缓存

缓存一词在计算中无处不在。 在应用程序设计的上下文中,它通常用于描述应用程序开发人员利用单独的内存或低延迟数据结构,缓存是临时存储或引用信息的副本,应用程序可能会在稍后的某个时间点重用,从而减轻重新访问或重新创建它的成本。

在 Java Caching API 的上下文中, Caching 描述了 Java 开发人员使用 Caching Provider 临时缓存 Java 对象的技术。 通常假设正在缓存来自数据库的信息。 然而,这不是缓存的必要条件。 从根本上说,任何生产或访问昂贵或耗时的信息都可以存储在缓存中。 一些常见的用例是:

  • client side caching of Web service calls Web 服务调用的客户端缓存
  • caching of expensive computations such as rendered images 缓存昂贵的计算,例如渲染图像
  • caching of data 数据缓存
  • servlet response caching servlet 响应缓存
  • caching of domain object graphs 域对象图缓存
目标
  • 为应用程序提供缓存功能,特别是缓存 Java 对象的能力;
  • 定义一套通用的缓存概念和设施;
  • 最大限度地减少 Java 开发人员需要学习采用缓存的概念数量;
  • 最大化在缓存实现之间使用缓存的应用程序的可移植性;
  • 支持进程内和分布式缓存实现;
  • 支持按值和可选的按引用缓存 Java 对象;
  • 根据 JSR-175 定义运行时缓存注释:Java 的元数据工具编程语言; 以便 Java 开发人员使用可选的注解处理器,来声明式地指定应用程序缓存要求;
Java 缓存 API 未解决
  • 资源和内存约束配置 - 虽然许多缓存实现支持限制缓存在运行时可能使用的资源量,但本规范并未定义如何配置或表示此功能。 然而,该规范确实为开发人员定义了一种标准机制,以指定信息应该可以缓存多长时间。

  • 缓存存储和拓扑——本规范没有指定缓存实现如何存储或表示被缓存的信息。

  • 管理 - 本规范未指定如何管理缓存。 它确实定义了通过 Java 管理扩展 (JMX) 以编程方式配置缓存和调查缓存统计信息的机制。

  • 安全性——本规范未指定如何保护缓存内容或如何控制对缓存的访问和操作。

  • 外部资源同步 - 本规范没有指定应用程序或缓存实现应如何保持缓存和外部资源内容同步。

虽然开发人员可以利用规范提供的通读和通写技术,但这些技术仅在缓存是唯一改变外部资源的应用程序时才有效。 在此场景之外,无法保证缓存同步。

提供的java chacing api的包是javax.cache.,maven获取方式

        
            javax.cache
            cache-api
            1.1.0
        
基础知识 核心概念

Java Caching API 定义了五个核心接口:CachingProviderCacheManagerCacheEntryExpiryPolicy

  • CachingProvider 定义了建立、配置、获取、管理和控制零个或多个 CacheManager 的机制。 应用程序可以在运行时访问和使用零个或多个 CachingProvider

  • CacheManager 定义了建立、配置、获取、管理和控制零或多个唯一命名的Cache都在CacheManager的上下文中的机制。一个CacheManager由单个 CachingProvider拥有。

  • Cache 是一种类似于 Map 的数据结构,它允许临时存储基于键的值,有些类似于java.util.Map数据结构。一个 Cache 由一个CacheManager拥有。

  • Entry是由缓存存储的单个键值对。

  • Cache存储的每个Entry都有一个定义的持续时间,称为到期持续时间(有效时长),在此期间它们可以被访问、更新和删除。一旦该持续时间过去,则该条目被称为已过期。一旦过期,条目就不再可供访问、更新或删除,就好像它们从未存在于缓存中一样。使用ExpiryPolicy设置到期。

    #mermaid-svg-jbatAfqaV7ST1pjE {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jbatAfqaV7ST1pjE .error-icon{fill:#552222;}#mermaid-svg-jbatAfqaV7ST1pjE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jbatAfqaV7ST1pjE .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-jbatAfqaV7ST1pjE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jbatAfqaV7ST1pjE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jbatAfqaV7ST1pjE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jbatAfqaV7ST1pjE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jbatAfqaV7ST1pjE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jbatAfqaV7ST1pjE .marker.cross{stroke:#333333;}#mermaid-svg-jbatAfqaV7ST1pjE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jbatAfqaV7ST1pjE g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-jbatAfqaV7ST1pjE g.classGroup text .title{font-weight:bolder;}#mermaid-svg-jbatAfqaV7ST1pjE .nodeLabel,#mermaid-svg-jbatAfqaV7ST1pjE .edgeLabel{color:#131300;}#mermaid-svg-jbatAfqaV7ST1pjE .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-jbatAfqaV7ST1pjE .label text{fill:#131300;}#mermaid-svg-jbatAfqaV7ST1pjE .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-jbatAfqaV7ST1pjE .classTitle{font-weight:bolder;}#mermaid-svg-jbatAfqaV7ST1pjE .node rect,#mermaid-svg-jbatAfqaV7ST1pjE .node circle,#mermaid-svg-jbatAfqaV7ST1pjE .node ellipse,#mermaid-svg-jbatAfqaV7ST1pjE .node polygon,#mermaid-svg-jbatAfqaV7ST1pjE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jbatAfqaV7ST1pjE .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-jbatAfqaV7ST1pjE g.clickable{cursor:pointer;}#mermaid-svg-jbatAfqaV7ST1pjE g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-jbatAfqaV7ST1pjE g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-jbatAfqaV7ST1pjE .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-jbatAfqaV7ST1pjE .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-jbatAfqaV7ST1pjE .dashed-line{stroke-dasharray:3;}#mermaid-svg-jbatAfqaV7ST1pjE #compositionStart,#mermaid-svg-jbatAfqaV7ST1pjE .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #compositionEnd,#mermaid-svg-jbatAfqaV7ST1pjE .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #dependencyStart,#mermaid-svg-jbatAfqaV7ST1pjE .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #dependencyStart,#mermaid-svg-jbatAfqaV7ST1pjE .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #extensionStart,#mermaid-svg-jbatAfqaV7ST1pjE .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #extensionEnd,#mermaid-svg-jbatAfqaV7ST1pjE .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #aggregationStart,#mermaid-svg-jbatAfqaV7ST1pjE .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE #aggregationEnd,#mermaid-svg-jbatAfqaV7ST1pjE .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jbatAfqaV7ST1pjE .edgeTerminals{font-size:11px;}#mermaid-svg-jbatAfqaV7ST1pjE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
    manage
    0..*
    1
    0..*
    manage
    0..*
    «interface»
    CachingProvider
    «interface»
    CacheManager
    «interface»
    Cache
    «interface»
    Entry
    «interface»
    ExpiryPolicy

按值存储和按引用存储

Cache 存储 Entry 的方式有两种。默认机制称为按值存储,在javax.cache.configuration.MutableConfiguration中由isStoreByValue控制,默认值true

它指示实现在将应用程序提供的键值对在缓存之前先制作它们的副本(复制),然后在从缓存中访问时返回条目的新副本。复制存储在缓存中的条目以及从缓存返回时再次复制条目的目的是允许应用程序继续改变键和值的状态,而不会对缓存所保存的条目产生其他副作用。

Java 序列化可以用来制作键和值的副本的简单方法实现。

为确保实现的应用程序可移植性,建议自定义键和值类在使用按值存储时实现并采用标准 Java 序列化。

实现用于制作条目的键和值的副本的机制可以是自定义的。然而,为了确保应用程序的可移植性,实现必须允许应用程序单独使用标准 Java 序列化。实现不得强制应用程序采用非标准 Java 序列化。

另一种可选的机制,称为按引用存储,指示Cache实现简单地存储和返回对应用程序提供的键和值的引用,而不是按值存储方法需要的副本。如果应用程序以后使用按引用存储的语义修改了提供给Cache的键或值,那么访问Cache条目的人就可以看到这些修改的副作用,而不需要应用程序更新Cache。

对于在 Java 堆上实现的缓存,按引用存储是更快的存储技术。

Map与Cache的异同点

相同点:

  • 缓存的value值通过关联的key进行存储和访问
  • 缓存中的每个key只能与单个value相关联。
  • 如果将可变的对象用作key,则必须非常小心。 如果key在与缓存一起使用时,key以影响相等比较的方式发生变化,则缓存的行为是不确定的。
  • 缓存依赖于相等的概念来确定键和值何时相同。 因此,自定义键和值类应该定义 Object.equals方法的合适实现。
  • 自定义键类应另外提供Object.hashCode方法的合适实现。

不同点:

  • 缓存的keys和values不能为null。

    任何对键或值使用 null 的尝试都将导致抛出 NullPointerException,无论使用如何。

  • 条目可能会过期。

    确保条目不再可用于应用程序,因为它们不再被视为有效,这个过程称为“到期”

  • 条目可能会被驱逐。

    • 缓存通常不配置为存储整个数据集。 相反,它们通常用于存储整个数据集的一个小的、经常使用的子集。

    • 为了确保缓存的大小不会无限制地消耗资源,缓存的实现可以定义一个策略来限制缓存在运行时可以使用的资源量,方法是在超出资源限制时删除某些条目。

    • 当缓存超过资源限制时从缓存中删除条目的过程称为“驱逐”。 当一个条目由于资源限制而从缓存中删除时,它被称为“被驱逐”。

    • 虽然规范没有定义缓存的容量,但一个明智的实现将定义表示所需容量限制的机制,以及一旦达到该容量就选择和驱逐条目的合适策略。 例如:LRU 驱逐策略试图驱逐最近最少使用的条目。

    • 规范中未定义容量的一些原因是:

      • 实现可以利用多层分层存储结构,从而定义每层的容量。 在这种情况下,不可能定义缓存的整体容量,这样做会很模糊。

      • 实现可以根据字节而不是每层的条目数来定义容量。

      • 条目在内存使用方面的相对成本与运行时条目实现的内部表示直接相关。

  • 为了支持比较和交换 (CAS) 操作,即那些以原子方式比较和交换值的操作,自定义值类应该提供Object.equals的合适实现。

    尽管推荐,但实现不一定需要调用自定义键类定义的Object.hashCodeObject.equals方法。 实现可以自由使用优化,从而避免调用这些方法。

    由于本规范没有定义对象等价的概念,因此应注意使用自定义键类并依赖实现特定优化来确定等价的应用程序可能不可移植。

  • 实现可能要求键和值以某种方式可序列化。

  • 缓存可以配置为控制条目的存储方式,使用按值存储或可选地使用按引用存储语义

  • 实现可以选择强制执行安全限制。 如果发生违规,必须抛出SecurityException

尽管推荐,但实现不一定需要调用自定义键类定义的Object.hashCodeObject.equals方法。 实现可以自由使用优化,从而避免调用这些方法。

由于本规范没有定义对象等价的概念,因此应注意使用自定义键类并依赖实现特定优化来确定等价的应用程序可能不可移植。

一致性

所有实现都必须支持如下所述的默认一致性模型。

默认一致性

当使用默认的一致性模式时,大多数缓存操作的执行就像缓存中的每个键都存在锁定机制一样。 当缓存操作在某个键上获得独占读写锁时,该键上的所有后续操作都将阻塞,直到该锁被释放。 结果是一个线程执行的操作发生在另一个线程执行的读取或变异操作之前,包括不同Java虚拟机中的线程。

可以理解为一个悲观锁,以加锁,修改,解锁来保证一致性。

对于某些缓存操作,缓存返回的值被认为是最后一个值。 最后一个值可能是旧值或新值,尤其是在同时更新条目的情况下。 返回哪个取决于实现。

这可以理解为一种没有锁的方法,没有保证一致性。其他操作遵循不同的约定,因为只有在条目的当前状态与所需状态匹配时才会发生突变。 在这样的操作中,多个线程可以自由竞争以应用这些更改,即好像它们共享一个锁一样。 这些是:

  boolean putIfAbsent(K key, V value);
  boolean remove(K key, V oldValue);
  boolean replace(K key, V oldValue, V newValue);
  boolean replace(K key, V value);
  V getAndReplace(K key, V value);

这可以理解为乐观锁的方式; 仅当状态与已知状态匹配时才应用更改,否则失败。 在同样以这种方式操作的 CPU 指令之后,这些类型的操作也称为比较和交换 (CAS) 操作。

由于这些方法必须与其他缓存操作进行交互,就好像它们具有排他锁一样,CAS 方法不能写入新值,除非它们也具有排他锁。

结果,在默认一致性中,虽然 CAS 方法可以允许更高级别的并发性,但它们将被非 CAS 方法阻止。

下表显示了适用于每种缓存方法的默认一致性。

MethodDefault Consistencyboolean containsKey(K key)last valueV get(K key)happen-beforeMap getAll(Collection
关注
打赏
1663402667
查看更多评论
立即登录/注册

微信扫码登录

0.0390s