Я пытаюсь найти одну или несколько одновременных коллекций для использования, чтобы я мог реализовать следующее поведение (имена придуманы для целей аналогии):
/**
* Acts as a broker for a concurrent hash map that stores its keys in order
* of submission. At shipping time, the concurrent map is "sealed"
* (picture a truck with its cargo door being closed)
* and its contents presented as an immutable map, and is replaced
* by a new concurrent map ready to accept values.
*
* Consumers of this class that submit information to it, are expected to
* know that this contains a concurrent collection, and should use the
* compareAndSet paradigm, e.g. the following:
*
* LoadingDock loadingDock = ...
* boolean done = false;
* while (!done)
* {
* V oldValue = loadingDock.get();
* V newValue = computeNewValue(oldValue, otherInformation);
* if (oldValue == null)
* done = loadingDock.putIfAbsent(newValue) == null;
* else
* done = loadingDock.replace(oldValue, newValue) == oldValue;
* }
*
*
* Keys and values must be non-null. Keys are not ordered.
*/
class LoadingDock<K,V>
{
/**
* analogous to ConcurrentMap's replace, putIfAbsent, and get methods
*/
public boolean replace(K key, V oldValue, V newValue);
public V putIfAbsent(K key, V value);
public V get(K key)
/* see above */
public Map<K,V> ship();
}
У меня есть две проблемы с этим.
Во-первых, ни Java, ни Guava не содержат ConcurrentLinkedHashMap. Это заставляет меня задуматься, почему нет - может быть, я скучаю по тонкостям такого зверя. Похоже, я мог бы сделать это сам, украсив ConcurrentHashMap классом, который добавляет ключ к списку, если putIfAbsent()
когда-либо вызывается и возвращает ноль - мне не нужны какие-либо другие методы в ConcurrentHashMap, кроме тех, что выше, поэтому нет никакого способа добавить новый ключ на карту, кроме как через вызов putIfAbsent()
.
Другая, более коварная проблема заключается в том, что я не могу думать о том, как реализовать ship()
без блокировки синхронизации - когда вызывается ship (), LoadingDock должен перенаправлять все новые вызовы на новую карту. и не может вернуть старую карту, пока не будет уверена, что все одновременные записи выполнены. (В противном случае я бы просто использовал AtomicReference для хранения параллельной карты.)
Есть ли способ сделать это без синхронизации?