Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当我计划高效缓存多个值时,应该如何实现Guava缓存?_Java_Caching_Guava - Fatal编程技术网

Java 当我计划高效缓存多个值时,应该如何实现Guava缓存?

Java 当我计划高效缓存多个值时,应该如何实现Guava缓存?,java,caching,guava,Java,Caching,Guava,我有一个Java类,它有一个GuavaLoadingCache,在这个缓存中,我计划存储两个东西:活跃员工一天的平均工作时间和他们的效率。我正在缓存这些值,因为每次请求传入时计算这些值都很昂贵。此外,缓存的内容将每分钟刷新一次(refreshAfterWrite) 我曾考虑在这种情况下使用CacheLoader,但是,它的加载方法只为每个键加载一个值。在我的CacheLoader中,我计划执行以下操作: private Service service = new Service(); publ

我有一个Java类,它有一个Guava
LoadingCache
,在这个缓存中,我计划存储两个东西:活跃员工一天的平均工作时间和他们的效率。我正在缓存这些值,因为每次请求传入时计算这些值都很昂贵。此外,缓存的内容将每分钟刷新一次(
refreshAfterWrite

我曾考虑在这种情况下使用
CacheLoader
,但是,它的加载方法只为每个键加载一个值。在我的
CacheLoader
中,我计划执行以下操作:

private Service service = new Service();

public Integer load(String key) throws Exception {
    if (key.equals("employeeAvg"))
        return calculateEmployeeAvg(service.getAllEmployees());

    if (key.equals("employeeEff"))
        return calculateEmployeeEff(service.getAllEmployees());

    return -1;
}
对我来说,我发现这非常低效,因为为了加载这两个值,我必须调用
service.getAllEmployees()
两次,因为如果我错了,请纠正我,
缓存加载程序应该是无状态的

这让我想到使用
LoadingCache.put(key,value)
方法,这样我就可以创建一个实用程序方法,调用
service.getAllEmployees()
一次,并动态计算值。但是,如果我确实使用了
LoadingCache.put()
,我就不会有
refreshAfterWrite
功能,因为它依赖于缓存加载程序

我该如何提高效率

但是,如果我确实使用了
LoadingCache.put()
,我就不会有
refreshAfterWrite
功能,因为它依赖于缓存加载程序

我不确定,但是您可以从
load
方法内部调用它。我的意思是,像您那样计算请求的值,然后将
放入另一个。然而,这让人感觉很不舒服

如果
service.getAllEmployees
很昂贵,那么您可以缓存它。如果
calculateEmployeeAvg
calculateEmployeeEff
都很便宜,那么在需要时重新计算它们。否则,看起来您可以使用两个缓存

我想,一种同时计算两个值的方法可能是一个合理的解决方案。创建一个小的类对来聚合它们,并将其用作缓存值。只有一把钥匙


关于你自己的解决方案,它可能是微不足道的

class EmployeeStatsCache {
    private long validUntil;
    private List<Employee> employeeList;
    private Integer employeeAvg;
    private Integer employeeEff;

    private boolean isValid() {
        return System.currentTimeMillis() <= validUntil;
    }

    private synchronized List<Employee> getEmployeeList() {
        if (!isValid || employeeList==null) {
            employeeList = service.getAllEmployees();
            validUntil = System.currentTimeMillis() + VALIDITY_MILLIS;
        }
        return employeeList;
    }

    public synchronized int getEmployeeAvg() {
        if (!isValid || employeeAvg==null) {
             employeeAvg = calculateEmployeeAvg(getEmployeeList());
        }
        return employeeAvg;
    }

    public synchronized int getEmployeeEff() {
        if (!isValid || employeeAvg==null) {
             employeeAvg = calculateEmployeeEff(getEmployeeList());
        }
        return employeeAvg;
    }
}
class EmployeeStatCache{
私人长有效期;
私人名单雇员名单;
私人整数雇员平均工资;
私人整数雇员基金;
私有布尔值isValid(){

返回系统.CurrurnTimeMILLISH()看起来,你的问题源于使用字符串来表示值类型(有效java项目50)。相反,考虑定义一个合适的值类型来存储这些数据,并使用A来避免重新计算它们。

public static class EmployeeStatistics {
  private final int average;
  private final int efficiency;
  // constructor, getters and setters
}

Supplier<EmployeeStatistics> statistics = Suppliers.memoize(
    new Supplier<EmployeeStatistics>() {
  @Override
  public EmployeeStatistics get() {
    List<Employee> employees = new Service().getAllEmployees();
    return new EmployeeStatistics(
        calculateEmployeeAvg(employees),
        calculateEmployeeEff(employees));
  }});

你可能想考虑使用A。我实际上只是想用一个键,缓存一个JSONED版本的object@MiguelPortugal如果您只需要JSON版本,那么没问题,但是一个简单的、不可变的两个成员类就更好了。对于这样的实例,建议使用Guava缓存吗?它看起来像Guava cache用于存储多个对象,如
LoadingCache
,其中整数值是一个ID,其值是一个对应的IDemployee@MiguelPortugal确实如此。如果只有一个元素,那么您就不需要它。您只需要自己实现加载和过期,这听起来很简单。+++但这也是适用于原始的2元素缓存,这就是为什么我没有提到它的原因。+++您可以编写一个类缓存并重新计算三件事:
allEmployees
employeeAvg
、和
employeeEff
。尽管我想编写自己的类来缓存我需要的所有东西,但我不想重新发明轮子。哈哈,我会的很可能,坚持使用番石榴缓存看起来就像每次调用该方法时,
Supplier#get
都会重新计算值。我的理解正确吗?不,
Suppliers.memoize()
decorator缓存包装好的供应商的值,因此它只计算一次。如果使用
Suppliers.memoizeWithExpation())
每个时间限制只处理一次。或者,如果您使用我建议的其他模式,您可以定义更强大的缓存行为,代价是稍微复杂一点的
供应商
。看起来像
供应商。memoizewithexpatition()
是我需要的工具!谢谢你!很乐意帮助:)供应商真的很有用(对于日常用例来说,可以说比缓存更有用)。他们是一件很好的事情,可以让我习惯于使用它们。后续问题,在这篇文章中:我发现我不需要同步
CachedLoader.load()
不再。我的问题是,
Supplier.get()是线程安全的吗?
Supplier<EmployeeStatistics> statistics = new Supplier<EmployeeStatistics>() {
  private final Object key = new Object();
  private final LoadingCache<Object, EmployeeStatistics> cache =
      CacheBuilder.newBuilder()
        // configure your builder
        .build(
           new CacheLoader<Object, EmployeeStatistics>() {
             public EmployeeStatistics load(Object key) {
               // same behavior as the Supplier above
             }});

  @Override
  public EmployeeStatistics get() {
    return cache.get(key);
  }};