【发布时间】: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