Вопрос

Я пытаюсь устранить неполадку, которая связана с удалением объекта из 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 не "синхронизирован".

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

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

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

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

Ознакомьтесь с рекомендациями по Java на equals () и compareTo () .

Что делает эта функция 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

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

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

Collections.synchronizedMap(transactions);

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

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

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

Темы и блокировки

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top