Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.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 如何确保多个番石榴缓存不会相互锁定?_Java_Caching_Concurrency_Locking_Guava - Fatal编程技术网

Java 如何确保多个番石榴缓存不会相互锁定?

Java 如何确保多个番石榴缓存不会相互锁定?,java,caching,concurrency,locking,guava,Java,Caching,Concurrency,Locking,Guava,据我所知,番石榴的缓存默认锁定在一把钥匙上。因此,如果线程t1和线程t2都试图获取相同的密钥,那么实际上只有一个线程会加载它,而另一个线程等待第一个线程获取值,然后获取相同的值 这是一个非常好的默认行为,但如果您处理的是相互依赖的多个缓存,那么它就不是最佳的 我们所处的情况是,我们有多个缓存实例和多个线程。线程查询多个缓存以完成其工作。因此,缓存实例相互依赖。它实际上可以归结为以下场景: 螺纹t1 Value v1 = cache1.get(k, new Callable<Value>

据我所知,番石榴的缓存默认锁定在一把钥匙上。因此,如果线程t1和线程t2都试图获取相同的密钥,那么实际上只有一个线程会加载它,而另一个线程等待第一个线程获取值,然后获取相同的值

这是一个非常好的默认行为,但如果您处理的是相互依赖的多个缓存,那么它就不是最佳的

我们所处的情况是,我们有多个缓存实例和多个线程。线程查询多个缓存以完成其工作。因此,缓存实例相互依赖。它实际上可以归结为以下场景:

螺纹t1

Value v1 = cache1.get(k, new Callable<Value>() {
    Value call() {
        //do something
        Value v2 = cache2.get(k, doRealWorkCallable());
        Value v = calculateFrom(v2)
        return v;
    }
});
(当然,第二个线程的情况正好相反)

这带来了“可能不需要”计算值的成本,好处是不存在死锁线程的风险

有没有“更好”的方法来处理番石榴

编辑:下面是一个具体的例子 我们正在从无法控制的外部系统调用多个Web服务。这些Web服务提供的数据是分层的,并通过引用链接。例如:

class WSOrganization {
    Integer id;
    String name;
    List<Integer> employeeIds; //like a collection of foreign keys
}
class WSEmployee {
    Integer id;
    String name;
    Integer organizationId; //like a foreignkey
}
现在,我们想通过在EJB1和EJB2上使用
javax.interceptor.interceptor
来介绍缓存

@AroundInvoke
public Object aroundInvoke(InvocationContext invocation) {
    Object object = getElementFromCache(invocation);
    return object;
}
两个线程可能会以相反的顺序调用这两个方法,我们肯定不希望它们相互阻塞

EDIT2:使用Hashmaps实现getElementFromCache()的示例
Guava在为缓存执行Callable时似乎没有锁定密钥。否则,您提供的代码将始终死锁,例如:

getOrganization(1337):
    (contains employee X)
    getEmployee(x):
        getOrganization(1337) // deadlock by recursion!!!
各国:

这个方法提供了一个简单的替代传统的“如果缓存,则返回;否则创建,则缓存并返回”模式

请注意,我没有尝试过这一点,但仅从文档中可以看出,Guava似乎在多次运行您的Callable时出错


总之,这不是问题

你怎么可能有这样相互依赖的值呢?我不理解它在任何应用程序中的意义。我们调用外部应用程序的Web服务并检索分层数据。我将为这个问题添加一个具体的例子。忘记Guava缓存,您可能会如何正常执行?使用添加到上述问题的hashmaps实现getElementFromCache()(为什么不能将代码片段添加到注释中?)。
//in EJB 1
PrefetchedOrganization getOrganization(Integer orgId) {
    WSOrganization org = orgService.getOrganizationById(orgId);
    for (Integer employeeId : org.employeeIds) {
        WSEmployee employee = employeeService.getEmployeeById(employeeId);
        listOfEmployees.add(employee);
    }
    return createPrefetchedOrgWithEmployees(org, listOfEmployees);
}

//in EJB 2
PrefetchedEmployee getEmployee(Integer employeeId) {
    WSEmployee employee = employeeService.getEmployeeById(employeeId);
    PrefetchedOrganization orgOfEmployee = ejb2.getOrganization(employee.organisationId);
    return orgOfEmployee.employee(employeeId);
}
@AroundInvoke
public Object aroundInvoke(InvocationContext invocation) {
    Object object = getElementFromCache(invocation);
    return object;
}
Integer id = idFrom(invocation);
if (cache.containsKey(id)) {
    return cache.get(id);
} else {
    Object result = invocation.proceed();
    cache.put(id, result);
    return result;
}
getOrganization(1337):
    (contains employee X)
    getEmployee(x):
        getOrganization(1337) // deadlock by recursion!!!