Синхронизация с Guava HashBiMap и synchronizedBiMap - PullRequest
0 голосов
/ 27 февраля 2019

Я получаю исключение из метода putIfAbsent из Guava BiMap в многопоточной ситуации.Как я должен правильно защитить его от проблем с многопоточностью?

Я создаю карту следующим образом:

BiMap<Integer, java.net.URI> cache = com.google.common.collect.Maps.synchronizedBiMap(HashBiMap.create());

Тогда единственный раз, когда я изменяю карту, этоcache.clear(); или cache.putIfAbsent(a,b)

Я иногда видел эту трассировку стека:

java.lang.IllegalArgumentException: value already present: http://example.com
    at com.google.common.collect.HashBiMap.put(HashBiMap.java:279)
    at com.google.common.collect.HashBiMap.put(HashBiMap.java:260)
    at java.util.Map.putIfAbsent(Map.java:744)
    at com.google.common.collect.Synchronized$SynchronizedMap.putIfAbsent(Synchronized.java:1120)

Это ошибка в HashBiMap или synchronizedBiMap?Или мне нужно проделать дополнительную работу для обеспечения безопасности потоков?

Использование guava-25.0-jre и Java(TM) SE Runtime Environment 1.8.0_152-b16

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Это не имеет ничего общего с синхронизацией, но именно так работает BiMap.Вы можете легко воспроизвести его:

cache.putIfAbsent(1, URI.create("http://example.com"));
cache.putIfAbsent(2, URI.create("http://stackoverflow.com"));
System.out.println(cache);
// {1=http://example.com, 2=http://stackoverflow.com}
cache.putIfAbsent(3, URI.create("http://example.com"));
// java.lang.IllegalArgumentException: value already present: http://example.com

BiMap - это "карта, которая сохраняет уникальность как ее значений, так и ключей." Это означает, что вы не можете поместить example.com снова, даже под другим ключом.См. Также вики-страницу с описанием BiMap:

BiMap.put(key, value) выдаст IllegalArgumentException, если вы попытаетесь сопоставить ключ с уже существующим значением.Если вы хотите удалить любую существующую ранее запись с указанным значением, используйте BiMap.forcePut(key, value).

В вашем случае вы можете использовать forcePut и не ошибиться с исключением:

cache.forcePut(3, URI.create("http://example.com"));
System.out.println(cache);
// {2=http://stackoverflow.com, 3=http://example.com}
0 голосов
/ 27 февраля 2019

Поскольку BiMap обеспечивает отображение значений на ключи, а также обычное Map отображение ключей на значения, каждое значение может быть сопряжено только с одним ключом.Попытка связать значение с более чем одним уникальным ключом приведет к IllegalArgumentException, который вы видите.

Не похоже, что ваша проблема связана с потоками, скорее с данными.

Как пример, это вызовет аналогичное исключение.Проблема заключается в наличии значения «Bar» с двумя отдельными клавишами «Foo» и «Baz»:

    public static void main(String[] args) {
        BiMap<String, String> m = HashBiMap.create();
        m.put("Foo", "Bar");
        m.put("Baz", "Bar"); // Throws IllegalArgumentException "value already present"
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...