Как безопасно очистить карту одновременно - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь решить проблему, которая кажется мне довольно распространенной, но я не смог найти для нее хорошего решения.

В очень параллельной среде мне нужно правильно высвобождать ресурсы, когда сеанс клиента разрушается.Вот входные данные:

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

Вот мое текущее решение:

while (!resourceMap.isEmpty()) {
    Map<Integer, Resource> toDestroy = new HashMap<>(resourceMap);
    for (Resource resource : toDestroy.values()) {
        resource.destroy();
    }
    resourceMap.keySet().removeAll(toDestroy.keySet());
}

, которое существует только потому, что ConcurrentHashMap#values#iterator не всегда отражает параллельные путы к resourceMap.Мне не нравится этот код, и я предпочел бы код, подобный очереди, но, к сожалению, ConcurrentMap не предоставляет ничего подобного:

while ((Map.Entry<String, Resource> entry = resourceMap.removeAny()) != null) {
    entry.value().destroy();
}

Я ищу решение, похожее на код, подобный очереди, приведенный выше, илилюбые альтернативные подходы к этой проблеме.

Ответы [ 2 ]

0 голосов
/ 19 мая 2018

Мне не нравится этот код, и я предпочел бы код, подобный очереди, но, к сожалению, ConcurrentMap не предоставляет ничего подобного ...

Я бы просто использовал итератор, но потом сноваЯ не фанат Java 8.

while (!resourceMap.isEmpty()) {
    Iterator<Resource> iterator = resourceMap.values().iterator();
    while (iterator.hasNext()) {
       Resource resource = iterator.next();
       iterator.remove();
       resource.destroy();
    }
}

Важно отметить, что в этой модели есть условия гонки.Кто-то может получить ресурс, использовать его, но в то же время он уничтожается этим потоком.

0 голосов
/ 18 мая 2018

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

И у вас есть рабочий поток для опроса этой карты иуничтожить все, что он находит в нем.

Поскольку вы «ставите в очередь» элемент для запроса операции над ними, вы можете вместо этого использовать ExecutorService.(или напишите что-нибудь на основе очереди плюс рабочий поток, который суммирует со службой исполнителя).

Например, с использованием исполнителей

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ResourceDestroyer {
  ExecutorService es = Executors.newSingleThreadExecutor();
  //"destroy" will be executed by the worker thread
  public void destroyResource(Resource r) {
    es.submit(r::destroy);
  }
}
...