Я пишу фасад обмена сообщений, который принимает в произвольном POJOs и отправляет их по сети в формате JSON со следующим рабочим процессом:Эффективно Объединив Случаи ByteBuffer
- пользователь вызывает
MessagingFacade.sendMessage(Object)
- Займите ByteBuffer из бассейн, мы serailize сообщения в этот буфер
- Преобразовать POJO в формат JSON, вызывая
JsonSerializer.serialize(Object, ByteBuffer)
- Отправить закодированное сообщение по проводам
Transport.send(ByteBuffer)
, сохранить ссылку на обещание, что будет п otified, когда сообщение было отправлено - Приложите обратный вызов на обещание вернуть ByteBuffer в бассейн, когда он был записан провод
- Возвращение из
MessagingFacade.sendMessage(Object)
призывания
Это является относительно тривиальным использование -case для объединения ByteBuffers, поскольку мы можем вызывать clear()
, чтобы сбросить состояние, когда объект возвращается в пул.
Вместо того, чтобы писать свой собственный пул объектов, я попытался использовать те, которые уже предлагаются в Apache commons-pool
. Тем не менее, кажется, есть довольно большой нюанс с GenericObjectPool
и SoftReferenceObjectPool
...
При заимствовании/возвращении объектов, эти два бассейна используют hashCode()
и/или equals()
, чтобы определить соответствующий PooledObject<ByteBuffer>
. Это имеет очень реальные последствия для ByteBuffer
, учитывая equals()
и hashCode()
реализации включают оценку содержимого базового byte
массива:
- Очистка объекта - Когда
ByteBuffer
возвращается в пул, он имеет состояние «очищено ». Это просто связано с вызовомByteBuffer.clear()
. Это не обнуляет все байты в массиве, а это означает, чтоequals()
иhashCode()
дают разные результаты при возвратеByteBuffer
против того, когда он был заимствован. - Скорость оценки - Учитывая, что я Объединив экземпляры
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)
...
Похоже, вам понадобится реализация, которая использует 'IdentityHashMap' вместо обычного' HashMap'. – Kayaman