【问题标题】:Lock on object's field value锁定对象的字段值
【发布时间】:2018-08-13 14:43:55
【问题描述】:
我的微服务正在接收来自 rabbitMQ 的消息并将其存储在 CouchDB 中,
我正在创建多个消费者线程来处理它们,并且我的代码由于正在发生的竞争条件而引发 ConflictUpdateException,即
线程X、Y同时读取同一个Object的couch db值;线程 X 在线程 Y 之前更新了 Couch 中的记录,但是线程 Y
正在根据 X 之前的哈希值 (_rev) 更新记录
修改记录。
对象的唯一标识符是复合的:name+age+id,
如何只为相同的线程执行临界区
(姓名+年龄+身份证)?
我不想实现的可能方式:
锁定字符串值(姓名 + 年龄 + id)。
[作为一种不好的做法]
用于锁定的 String 和 CustomObjects 的 HashMap。
[因为我没有唯一对象计数的内存限制]
有什么建议吗?
【问题讨论】:
标签:
java
multithreading
performance
【解决方案1】:
我认为你应该跟踪_rev:
- 检索文档,记下 CouchDB 发送的 _rev 属性
- 编辑您需要的字段
- 使用 _rev 属性将更新后的文档发回
- 如果 _rev 与当前存储的数字匹配,则完成!
- 如果存在冲突(当 _rev 不匹配时),请检索最新的文档版本并再次编辑您需要编辑的内容。转到第 3 步
【解决方案2】:
你需要concurrentHashMap 结构,持有锁定的主键。
它们的表示由您决定,不鼓励的字符串与实现 hashcode+equals 的某些专用类的实例一样好。
您的消费者将遍历输入队列,尝试通过调用原子 putIfAbsent() 来锁定记录。如果成功,它将执行其 storeToDatabase() 调用,然后从该映射中进行 remove() 条目。否则移动到队列中的下一个条目。
通过这种方式,您将只需要在此锁定键映射中的少数(消费者计数)条目,
没有巨大的内存消耗,并行度会很高。但它不会保留传入的订单。