【问题标题】:how to lock free use two ConcurrentHashMap in java/scala?如何在 java/scala 中锁定免费使用两个 ConcurrentHashMap?
【发布时间】:2016-07-29 06:13:36
【问题描述】:

我很早就为这个问题头疼了,希望对你有所帮助。
我想用ConcurrentSkipListMap 存储许多Task,其中内部是ConcurrentHashMap,称为多段锁。
使用 scala 显示的简单示例代码(java 也可读):
val tasks = new ConcurrentSkipListMap[TaskKey, Task]() 将类简单地引用为:

class TaskKey(id: String, systemTime: Long)
用于标识Task的TaskKey类是唯一的,Task如下:

trait Task {
  val taskId: TaskKey //account and custom name
  def execute(): Unit //do the task
}

当我使用TaskKey操作我的HashMap时,我的HashMap是grate,但是HashMap几乎可以用id访问。所以,我必须定义另一个ConcurrentHashMap来存储id的映射到TaskKey:
val auxiliaryMap = new ConcurrentHashMap[String, TaskKey]()
让我们考虑一个添加和删除操作:

def get(taskId: String) = {
  Option(auxiliaryMap.get(taskId)).flatMap{x => //try get TaskKey
    //if TaskKey exist, try get it.
    Option(tasks.get(x)) //make null to None
  }
}

def remove(taskId: String) = {
  Option(auxiliaryMap.remove(taskId)).flatMap{ x => //try get TaskKey
    //if TaskKey exist, try remove it.
    Option(tasks.remove(x)) //make null to None
  }
}

很明显,虽然两个 Map 都是线程安全的,但是包装器使数据不一致。 如果我使用锁,多段 Map 变得毫无意义。我该如何处理使两个 ConcurrentHashMap 正常工作的问题?

另外,TaskKey包含一个systemTime变量,用于对数据进行排序,完整的ConcurrentSkipListMap定义如下:

val tasks = new ConcurrentSkipListMap[TaskKey, Task](new Comparator[TaskKey]() {
  override def compare(o1: TaskKey, o2: TaskKey): Int = {
    val compare = (o1.systemTime - o2.systemTime).toInt

    if (compare == 0) {
      o1.hashCode() - o2.hashCode()
    } else compare //distinct same time task
  }
})

如有遗漏,欢迎提出任何问题。

【问题讨论】:

  • 您能否澄清一下您的意思当我使用TaskKey 操作我的HashMap 时非常好,但实际上,HashMap 几乎可以通过id 访问。?有一些方法可以同步 2 个哈希图,但按照您最初的建议,将所有内容合二为一总是更好。
  • @Augusto, get(taskId: String) 用于获取Task 对象。我必须先获取TaskKey,然后才能获取Task。*barely* 表示我不能直接使用TaskKey可以使用 taskId 字符串获取数据。这就是我使用两个 HashMap 的原因。
  • 我自己也讨厌这样的cmets,但还是忍不住要问。您确定需要将任务 ID 作为字符串吗?也许只是使用 TaskKey 作为任务 id 并且只有一张地图?
  • @ArtemMalinko,你很小心,谢谢注意这一点。但我不能简单地使用 TaskKey。在这种情况下,我简化了一些我想做的逻辑。简而言之,有一个cancel(id: String) 操作来决定删除一个任务,但是Task 有一个nextTask 方法可以在完成后生成新任务。具有相同id 和不同systemTime 的TaskKey 的新任务。为了支持取消生成的任务,旧的TaskKey是没有意义的。所以,id是API用户对任务的唯一标记。

标签: java multithreading scala concurrenthashmap


【解决方案1】:

我正在使用消息队列将运算符扁平化到这些映射。此外,这种方式根本不需要并发哈希映射,但消息队列可能需要并发队列。

【讨论】:

    猜你喜欢
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 1970-01-01
    • 2022-07-18
    • 2019-12-05
    • 1970-01-01
    相关资源
    最近更新 更多