Параллельный набор со слабыми ссылками и идентификационным хэшем

Я хотел параллельный набор со слабыми ссылками на элементы. Я думал сделать это, используя MapMaker Гуавы:

Set<Object> concurrentSet = Collections.newSetFromMap(
    new MapMaker<Object, Boolean>().weakKeys().makeMap());

Guava автоматически предоставит вам хэши идентификации со слабыми ключами. Однако оказывается, что MapMaker не допускает параметров типа.

file.java:123 type com.google.common.collect.MapMaker does not take parameters
                new MapMaker<Object, Boolean>().weakKeys().makeMap());
                            ^

Любые решения, как я могу получить параллельный набор со слабыми ссылками на элементы?


person r.v    schedule 12.04.2013    source источник


Ответы (3)


Как описано в документации. , MapMaker не является универсальным типом; это <Object, Object>. Это означает, что вы можете поместить что угодно в качестве ключа или значения, вам просто нужно привести его при извлечении. Цитирую ссылку:

   ConcurrentMap<Request, Stopwatch> timers = new MapMaker()
       .concurrencyLevel(4)
       .weakKeys()
       .makeMap();

Чтобы получить Set с Map записями, просто вызовите Map#entrySet().

person m0skit0    schedule 12.04.2013
comment
Я хотел одновременный набор. Как мне получить набор от него тогда? - person r.v; 12.04.2013
comment
makeMap() является общим, поэтому ConcurrentMap<K, V> timers = new MapMaker() .concurrencyLevel(4) .weakKeys() .makeMap(); будет работать. - person Xaerxess; 12.04.2013
comment
@Xaerxess не заметил, что цитата удалила XML-теги :) Отформатировала как код, спасибо. - person m0skit0; 12.04.2013
comment
Вы все еще хотите Collections.newSetFromMap, как показано в исходном вопросе. - person Kevin Bourrillion; 13.04.2013

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

Java, без гуавы

Используя идиому, предложенную в документации по классу, используйте Collections.newSetFromMap, чтобы обернуть параллельную карту как набор. Использование Boolean в качестве типа значения карты является просто наполнителем, несущественным.

Set< YourObjectTypeGoesHere > concurrentWeakSet = 
    Collections.synchronizedSet(
        Collections.newSetFromMap(
            new WeakHashMap< YourObjectTypeGoesHere , Boolean >()
        )
    )
;

Можно вывести параметризованные типы, упростив код до:

Set< YourObjectTypeGoesHere > concurrentWeakSet = 
    Collections.synchronizedSet(
        Collections.newSetFromMap(
            new WeakHashMap<>()     // Types inferred, so omitted.
        )
    )
;

Гуава

В качестве альтернативы мы можем использовать MapMaker из библиотеки Google Guava.

Вместо того, чтобы использовать пример этого документа, заключающий в себе WeakHashMap мы заменяем WeakHashMap картой из Google Guava MapMaker согласно предложению документа Guava для позвоните new MapMaker().weakKeys().makeMap(). В документе Guava отмечается, что эта карта «сравнивает ключи, используя идентификатор объекта, тогда как WeakHashMap использует Object.equals».

использование

Пользоваться проще, чем понимать!

Чтобы создать экземпляр

Чтобы создать параллельный слабый набор, скопируйте и вставьте следующий код. Замените два вхождения YourObjectTypeGoesHere.

int level = 16; // Basically, the approximate number of threads that may simultaneously try to mutate the map. See Guava doc.
ConcurrentMap<YourObjectTypeGoesHere , Boolean> concurrentWeakMap = new MapMaker().concurrencyLevel( level ).weakKeys().makeMap(); // Google Guava team recommends MapMaker > weakKeys > makeMap as a replacement for weakHashMap.
Set<YourObjectTypeGoesHere> concurrentWeakSet = Collections.newSetFromMap( concurrentWeakMap ); // Concurrency protection carries over to Set wrapper.

Добавить

Чтобы добавить в набор:

concurrentWeakSet.add( myObject ); 

Итерация

Чтобы получить доступ к элементам в наборе:

Iterator<YourObjectTypeGoesHere> iterator = concurrentWeakSet.iterator();
while(iterator.hasNext()) {
    YourObjectTypeGoesHere myObject = iterator.next();
    if( myObject != null ) { // Not sure if needed. Is it possible for object to be garbage-collected but not yet have its entry removed from the Set/Map?
       // Work with the object.
    }
}

Удалять

Быть слабым означает, что нет необходимости удалять элементы. По мере того, как элементы становятся неиспользуемыми и удаляются сборщиком мусора, они исчезают из нашей коллекции (карты/набора).

person Basil Bourque    schedule 14.08.2014

Ваш оригинальный подход будет работать нормально, вам просто нужно указать параметры вашего типа при вызове makeMap()

Set<Object> concurrentSet = Collections.newSetFromMap(
new MapMaker().weakKeys().<Object, Boolean> makeMap());

с использованием менее используемого синтаксиса вызова общего метода Java. Спецификация Java.

person Stuart    schedule 04.08.2015