次のワークフローで、任意の POJO を取り込んでネットワーク経由で JSON 形式で送信するメッセージング ファサードを作成しています。
- ユーザーが呼び出す
MessagingFacade.sendMessage(Object)
- プールから ByteBuffer を借りて、メッセージをこのバッファにシリアル化します
- 呼び出して POJO を JSON に変換する
JsonSerializer.serialize(Object, ByteBuffer)
- エンコードされたメッセージをネットワーク経由で送信し、
Transport.send(ByteBuffer)
メッセージが送信されたときに通知される promise への参照を保持します。 - コールバックを promise にアタッチして、ByteBuffer がワイヤに書き込まれた後にプールに返すようにします。
MessagingFacade.sendMessage(Object)
呼び出しから戻る
clear()
オブジェクトがプールに返されたときに状態をリセットするために呼び出すことができることを考えると、これは ByteBuffers をプールするための比較的単純なユースケースです。
独自のオブジェクト プールを作成するのではなく、既に Apache で提供されているものを利用しようとしましたcommons-pool
。GenericObjectPool
ただし、 and SoftReferenceObjectPool
...にはかなり大きな注意点があるようです。
オブジェクトを借用/返却する場合、これらの 2 つのプールは関連する を識別するためにhashCode()
and/orを使用しています。との実装が基礎となる配列の内容の評価を伴うことを考えると、これは に非常に現実的な意味を持ちます。equals()
PooledObject<ByteBuffer>
ByteBuffer
equals()
hashCode()
byte
- オブジェクトのクリーニング -
ByteBuffer
がプールに戻されると、その状態は「クリーニング済み」になります。これには、 を呼び出すだけByteBuffer.clear()
です。これは、配列内のすべてのバイトをゼロにするわけではありません。つまり、equals()
をhashCode()
返すByteBuffer
ときと、借用したときの結果が異なります。 ByteBuffer
評価速度 -最大メッセージ サイズ (1MB) の容量で のインスタンスをプールしている場合、両方hashCode()
を評価し、equals()
この非常に大きな配列を直線的にトラバースする必要があります。
equals()
Apache commons-pool の実装は、(a) クラスのコストとhashCode()
実装が高いか、(b)hashCode()
クリーニング後に安定した結果が得られないユースケースには適していないようです。
GenericObjectPool
このユースケースを作成または機能させるための唯一の実行可能なオプションは、同一性等価/ハッシュコードロジックを使用する別のクラスでSoftReferenceObjectPool
ラップすることです。ByteBuffer
これは機能していますが、このユースケースがいかにバニラであるかを考えると、少し面倒に感じます。このアプローチに代わるより良い方法はありますか?
最後に 1 つ。の不安定性により、equals()
実際hashCode()
には から例外が発生しGenericObjectPool
ます。これは、プールから借用されたことのないオブジェクトを返そうとしているとプールが認識しているためです。
java.lang.IllegalStateException: Returned object not currently part of this pool
at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:537)
...