【问题标题】:Java: Fine grain locking for requests?Java:请求的细粒度锁定?
【发布时间】:2013-05-13 11:36:29
【问题描述】:

我正在尝试为以下场景创建细粒度锁定机制:

我有一个数据存储,其中包含许多序列化的Cache 对象。每个Cache 属于某个人、组或公司,每个Cache 可以通过以下四种方式之一进行修改:可以创建、删除、删除或插入。在修改 Cache 时,我想阻止对它的访问。每个Cache 都使用CacheLocation 对象标识,该对象存储目录和文件名以及完整路径以方便使用。

目前我在一个名为RequestQueue 的类中使用一个数组列表,该类包含当前正在处理的CacheLocation 对象。然后,当另一个线程进入时,它会检查队列以查看它所请求的CacheLocation 是否已被使用。如果是这种情况,则使用 while 循环定期检查 CacheLocation,直到将其放在那里的请求将其删除。

我在想,有一个 CacheLocation 键对 BlockingQueue 值的 HashMap 可能是一个想法。这会产生大量 BlockingQueue 对象,但我可以很好地管理队列。

有没有更好的方法来进行这种细粒度锁定?

【问题讨论】:

  • 不要使用 while 循环来等待资源。两个或多个线程可以同时具有条件为真并中断序列化访问。相反,使用同步或锁定
  • 我以前试过这个,但可能弄错了。我在 RequestMap 上调用 get 以查看请求 CacheLocation 是否在 Map 中(认为我需要使用 ConcurrentHashMap),如果 get 返回了一个我正在同步并在对象上调用 wait 的位置。我遇到的问题是从另一个线程调用通知导致 IllegalMonitorStateException。不知道为什么,因为其他线程应该已经创建了对象,但它需要更多的研究:)

标签: java concurrency locking request-queueing


【解决方案1】:

如果我正确理解了您的描述,让您的设计保持相当简单的一种方法是:

  • 使用ConcurrentHashMap<CacheLocation, Cache> 来存储缓存(我假设CacheLocations 是不可变的,或者至少从不变异)
  • 确保通过锁定相关的CacheLocation 对象来保护对缓存的所有访问

【讨论】:

  • 是的,CacheLocation 对象是不可变的。我目前使用 ConcurrentHashMap 将当前加载的缓存存储到内存中,而不是从磁盘读取它们,直到所有使用 Cache 的用户都发送了完成的请求。所以我可以使用相同的技术来存储我猜的请求:)我会试一试,让你知道我是怎么得到的:)
  • 感谢大家的帮助,通过创建一个以 CacheLocation 为键并以 ReentrantLock 为值的 ConcurrentHashMap 来使其正常工作。当更改请求进入时,它会检查映射,如果该 CacheLocation 的条目不存在,它会创建一个新锁,通过调用 lock() 获取它并将其添加到映射中。如果条目存在,它会获取锁并调用 lock() 导致线程等待。一旦拥有锁的线程释放它,下一个线程就会获取它,依此类推。这使我的设计保持美观整洁,希望快速 =) 再次感谢大家
  • @AlexeiBlue 这是一种方式——我更多地考虑使用synchronized(cacheLocation) 块来保持简单。但是效果是一样的。
【解决方案2】:

还有另一种非阻塞(但可能更慢)的方法:

map.compute(someId, (key, value) -> {
  // atomic access to cache
  return null;
});

阅读here我的相关问题和答案

【讨论】:

    猜你喜欢
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多