java - 同步缓存项目

标签 java multithreading caching guava

我正在使用类似的东西

Cache<Integer, Item> cache;

其中Item彼此独立,看起来像

private static class Item {
    private final int id;
    ... some mutable data

    synchronized doSomething() {...}
    synchronized doSomethingElse() {...}
}

这个想法是从缓存中获取项目并对其调用同步方法。万一错过了,可以重新创建该项目,这很好。

当一个项目从缓存中逐出并重新创建时,当线程运行同步方法时,就会出现问题。一个新线程获取一个新项目并对其进行同步...因此,对于单个 id,同步方法内有两个线程。失败。

有没有简单的方法可以解决这个问题?这是Guava Cache ,如果有帮助的话。

最佳答案

我认为Louis的建议,使用 key 来锁定是最简单实用的。这是代码片段,在没有 Guava 库的帮助下,说明了这个想法:

static locks[] = new Lock[ ... ];
static { /* initialize lock array */ } 
int id;
void doSomething() {
  final lock = locks[id % locks.length];
  lock.lock();
  try {
    /* protected code */
  } finally {
    lock.unlock();
  } 
}

锁数组的大小限制了您获得的最大并行度。如果您的代码仅使用 CPU,您可以通过可用处理器的数量来初始化它,这是完美的解决方案。如果您的代码等待 I/O,您可能需要任意大的锁数组,或者限制可以运行关键部分的线程数量。在这种情况下,另一种方法可能会更好。

更概念层面的评论:

如果您想防止项目被逐出,您需要一种名为固定的机制。在内部,大多数缓存实现都使用它,例如用于在 I/O 操作期间阻塞。某些缓存可能会公开应用程序执行此操作的方法。

在JCache兼容的缓存中,有EntryProcessor的概念。 EntryProcessor 允许您以原子方式处理条目上的代码。这意味着缓存正在为您完成所有锁定。根据问题的范围,这可能有一个优势,因为这也适用于集群场景,这意味着锁定是集群范围的。

我想到的另一个想法是可否决驱逐。这是 EHCache 3 正在实现的概念。通过指定可否决的逐出策略,您可以自行实现固定机制。

关于java - 同步缓存项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34236241/

相关文章:

java - 通过Java代码关闭MQ channel

java - jackson - 在序列化时省略字段名称

ruby-on-rails - Ruby with_advisory_lock 多线程测试间歇性失败

php - 来自静态域或子域的 Symfony2 Assets 资源

caching - CMake 使用命令行覆盖缓存变量

java - 如何检测 Mac OsX 10.7 上是否下载了 JavaVM

java - 短信发送错误

带有 mod_jk : maxThread setting upon load balancing 的 Apache + Tomcat

java - java中的多线程持久队列

caching - 缓存行锁定