2015-04-09 6 views
2

Я пишу фасад обмена сообщений, который принимает в произвольном POJOs и отправляет их по сети в формате JSON со следующим рабочим процессом:Эффективно Объединив Случаи ByteBuffer

  1. пользователь вызывает MessagingFacade.sendMessage(Object)
  2. Займите ByteBuffer из бассейн, мы serailize сообщения в этот буфер
  3. Преобразовать POJO в формат JSON, вызывая JsonSerializer.serialize(Object, ByteBuffer)
  4. Отправить закодированное сообщение по проводам Transport.send(ByteBuffer), сохранить ссылку на обещание, что будет п otified, когда сообщение было отправлено
  5. Приложите обратный вызов на обещание вернуть ByteBuffer в бассейн, когда он был записан провод
  6. Возвращение из MessagingFacade.sendMessage(Object) призывания

Это является относительно тривиальным использование -case для объединения ByteBuffers, поскольку мы можем вызывать clear(), чтобы сбросить состояние, когда объект возвращается в пул.


Вместо того, чтобы писать свой собственный пул объектов, я попытался использовать те, которые уже предлагаются в Apache commons-pool. Тем не менее, кажется, есть довольно большой нюанс с GenericObjectPool и SoftReferenceObjectPool ...

При заимствовании/возвращении объектов, эти два бассейна используют hashCode() и/или equals(), чтобы определить соответствующий PooledObject<ByteBuffer>. Это имеет очень реальные последствия для ByteBuffer, учитывая equals() и hashCode() реализации включают оценку содержимого базового byte массива:

  1. Очистка объекта - Когда ByteBuffer возвращается в пул, он имеет состояние «очищено ». Это просто связано с вызовом ByteBuffer.clear(). Это не обнуляет все байты в массиве, а это означает, что equals() и hashCode() дают разные результаты при возврате ByteBuffer против того, когда он был заимствован.
  2. Скорость оценки - Учитывая, что я Объединив экземпляры ByteBuffer с емкостью моего максимального размера сообщения (1 МБ), оценивая как hashCode() и equals() имеет линейно перемещаться этот очень большой массив

Реализации Apons для общих ресурсов не подходят для использования в случае, когда либо (a) класс имеет дорогие equals() и hashCode(), либо (b) hashCode() не дает стабильных результатов после очистки.

Единственный жизнеспособный вариант, чтобы сделать GenericObjectPool или SoftReferenceObjectPool Работаем для этого случая использования, кажется, нужно обернуть ByteBuffer в другом классе, который использует логику равенства идентичности/хэш-кода.

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


Последняя заметка; из-за нестабильности equals() и hashCode() один будет на самом деле получить исключения из GenericObjectPool, потому что бассейн считает, что вы пытаетесь вернуть объект, который никогда не borrrowed из бассейна:

java.lang.IllegalStateException: Returned object not currently part of this pool 
at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:537) 
... 
+0

Похоже, вам понадобится реализация, которая использует 'IdentityHashMap' вместо обычного' HashMap'. – Kayaman

ответ

2

Ограничение вы имеете в виду было идентифицированные в JIRA, выпуски POOL-283 и POOL-284, которые были разрешены в версии 2.4.1 Commons Pool. Попробуйте перейти на версию 2.4.1.

Смежные вопросы