странное поведение HashMap.put () - PullRequest
1 голос
/ 14 января 2009

Я пытаюсь устранить неполадку, которая, как представляется, связана с удалением объекта из HashMap и последующим возвращением того же объекта с использованием нового ключа. Моя HashMap создается следующим образом:

transactions = new HashMap<Short, TransactionBase>();

Код, который выполняет переназначение, выглядит следующим образом:

transactions.remove(transaction.tran_no);
transaction.tran_no = generate_transaction_id();
transactions.put(transaction.tran_no, transaction);

Периодическое поведение, которое я наблюдаю, состоит в том, что код, который выполняется сразу после этого, который зависит от того, доступен ли объект транзакции, не находит объект транзакции, используя новый идентификатор транзакции. Однако в какой-то момент в будущем транзакция может быть обнаружена. Итак, потянув за соломинку, есть ли какой-нибудь асинхронный эффект для put () или remove, который может вызвать такое поведение?

Я должен отметить, что, насколько мне известно, доступ к контейнеру осуществляется только одним потоком. Я уже прочитал в своей документации, что класс HashMap не "синхронизирован".

Ответы [ 9 ]

7 голосов
/ 15 января 2009

Существует небольшая разница между удалением / получением и положением (хотя я предполагаю, что у вас есть проблема с многопоточностью).

Параметр для remove / get имеет тип Object; для put это тип K. Причина этого была изложена много раз ранее. Это значит, что у него проблемы с боксом. Я даже не собираюсь угадывать, каковы правила. Если значение помечается как Byte в одном месте и Short в другом, то эти два объекта не могут быть равны.

Существует похожая проблема с List.remove(int) и List.remove(Object).

6 голосов
/ 15 января 2009

Я предполагаю, что каждый раз, когда вы проверяете наличие предмета, вы определенно используете short или Short argument до Map.get() или Map.contains()?

Эти методы принимают аргументы объекта, поэтому, если вы передадите им int, он будет преобразован в Integer и никогда не будет соответствовать ни одному элементу вашей карты, поскольку все они будут иметь Short ключей.

4 голосов
/ 15 января 2009

В классе HashMap нет «асинхронных» эффектов. Как только вы положили что-то туда, оно там. Вы должны проверить дважды и трижды, чтобы убедиться, что нет проблем с многопоточностью.

Единственное, о чем я могу думать, это то, что вы где-то делаете копию HashMap. Очевидно, что на копию не повлияет добавление материала в оригинал или наоборот.

2 голосов
/ 15 января 2009

Вы переопределили equals(), но не hashCode() в объектах вашей модели? Как насчет compareTo()? Если вы поймете это неправильно, Коллекции действительно будут вести себя странно.

Проверьте Java Practices на равно () и compareTo () .

2 голосов
/ 15 января 2009

Только одно предложение ... вы сосредотачиваетесь на доступе к HashMap, но мне интересно, стоит ли вам также посмотреть, является ли ваш generate_transaction_id () поточно-ориентированным или он ведет себя неожиданным образом.

1 голос
/ 15 января 2009

Что делает эта функция generate_transaction_id ()? Если он генерирует 16-битный GUID-подобный объект, вы можете легко получить хеш-коллизии. В сочетании с многопоточностью вы можете получить:

T1: transaction1.tran_no = generate_transaction_id();    => 1729
T2: transaction2.tran_no = generate_transaction_id();    => 1729
T1: transactions.put(transaction1.tran_no, transaction1); => map.put(1729, transaction1)
T2: transactions.put(transaction2.tran_no, transaction2); => map.put(1729, transaction2)
T1: int tran_no = transactions.get(1729);               => transaction2
T1: transactions.remove(transaction.tran_no);           => map.remove(1729)
T2: int tran_no = transactions.get(1729);               => null

Конечно, это могло бы быть решением, только если это «насколько вам известно» неверно.

1 голос
/ 15 января 2009

Итак, вы знаете, HashMap не безопасен для потоков. Вы уверены, что к нему обращается только один поток? В конце концов, прерывистые сбои часто связаны с потоками. Если нет, вы можете обернуть его в Collections.synchronizedMap(), например:

Collections.synchronizedMap(transactions);

Вы всегда можете просто попробовать, чтобы исключить эту возможность.

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

0 голосов
/ 03 июля 2009

Как уже отмечали другие, вы ДОЛЖНЫ знать, доступен ли HashMap только одним потоком или нет. CollectionSpy - это новый профилировщик, который позволяет мгновенно определить для всех контейнеров, сколько потоков выполняет какой-либо доступ. Подробнее см. www.collectionspy.com .

0 голосов
/ 15 января 2009

Потоки уже упоминались в нескольких ответах, но рассматривали ли вы проблему видимости для объектов, используемых несколькими потоками? Возможно (и довольно часто), что если вы поместите объект в коллекцию в одном потоке, он не будет «опубликован» в других потоках, если вы не синхронизировались в коллекции должным образом.

Резьбы и замки

Синхронизация и безопасность потоков в Java

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...