как заблокировать бесплатное использование двух ConcurrentHashMap в java/scala?

Я давно мучаюсь с этой проблемой, надеюсь на какую-то помощь.
Я хочу хранить много Task с ConcurrentSkipListMap, внутреннее значение которого ConcurrentHashMap известно как многосегментная блокировка.
Простой пример кода, показанный со scala (java также читаем ):
val tasks = new ConcurrentSkipListMap[TaskKey, Task]() ссылаться на простой класс как:

class TaskKey(id: String, systemTime: Long)
Класс TaskKey, используемый для идентификации Task, уникален, и Task выглядит следующим образом:

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

Когда я использую TaskKey для работы, моя HashMap невозможна, но на самом деле HashMap едва может получить доступ с идентификатором. Итак, я должен определить другой ConcurrentHashMap для хранения сопоставления идентификатора с 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
  }
}

Очевидно, что хотя обе карты являются потокобезопасными, оболочка делает данные несогласованными. Если я использую блокировку, многосегментная карта становится бессмысленной. Как я могу решить проблему, чтобы два ConcurrentHashMap работали хорошо?

Кроме того, TaskKey содержит системную переменную Time, используемую для сортировки данных, полное 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
  }
})

любые вопросы приветствуются, если я что-то пропустил.


person LoranceChen    schedule 29.07.2016    source источник
comment
Не могли бы вы пояснить, что вы подразумеваете под Когда я использую TaskKey для работы с моей HashMap, это здорово, но на самом деле HashMap едва может получить доступ с идентификатором.? Есть несколько подходов к синхронизации двух хэш-карт, но всегда лучше иметь все в одном, как вы предлагали изначально.   -  person Augusto    schedule 29.07.2016
comment
@Augusto, get(taskId: String) используется для получения объекта Task. Я должен получить TaskKey, прежде чем получить Task. *Едва* означает, что я не могу использовать TaskKey напрямую и могу получать данные только со строкой taskId. Вот почему я использую два HashMap.   -  person LoranceChen    schedule 29.07.2016
comment
Я сам ненавижу такие комментарии, но не могу не спросить. Вы уверены, что вам нужен идентификатор задачи в виде строки. Может быть, просто использовать TaskKey в качестве идентификатора задачи и иметь только одну карту?   -  person Artem Malinko    schedule 29.07.2016
comment
@ArtemMalinko, вы очень осторожны, спасибо, обратите внимание. Но я не могу просто использовать TaskKey. В ситуации я упрощаю некоторую логику, что я хочу сделать. Короче говоря, есть операция cancel(id: String) для решения об удалении задачи, но у задачи есть метод nextTask, который может генерировать новую задачу, когда она будет выполнена. Новая задача с другим TaskKey, который имеет тот же id и другой systemTime. Чтобы поддерживать отмену сгенерированной задачи, старый TaskKey не имеет смысла. Итак, id — это уникальная метка для задачи с точки зрения пользователя API.   -  person LoranceChen    schedule 29.07.2016


Ответы (1)


Я использую очередь сообщений, чтобы сгладить оператор для этих карт. Кроме того, этот способ вообще не требует concurrenthashmap, но очереди сообщений может потребоваться параллельная очередь.

person LoranceChen    schedule 31.07.2016