...
PlantUML |
---|
@startuml
interface AutoCloseable {
void close()
}
interface ByteBufferSharing extends AutoCloseable {
ByteBuffer getBuffer()
ByteBuffer expandWriteBufferIfNeeded(int newCapacity)
ByteBuffer expandReadBufferIfNeeded(int newCapacity)
}
class ByteBufferVendor {
ByteBufferVendor(ByteBuffer bufferArg, BufferType bufferType, BufferPool bufferPool)
ByteBufferSharing open()
ByteBufferSharing open(long time, TimeUnit unit)
void destruct()
}
interface ByteBufferVendor.ByteBufferSharingInternal extends ByteBufferSharing {
void releaseBuffer()
}
class ByteBufferVendor.ByteBufferSharingInternalImpl implements ByteBufferVendor.ByteBufferSharingInternal {}
ByteBufferVendor "sharing" *-- ByteBufferVendor.ByteBufferSharingInternal
ByteBufferVendor "lock" *-- ReentrantLock
ByteBufferVendor "isDestructed" *-- AtomicBoolean
ByteBufferVendor "counter" *-- AtomicInteger
ByteBufferVendor.ByteBufferSharingInternalImpl "buffer\n0..1" --> "1" ByteBuffer
ByteBufferVendor.ByteBufferSharingInternalImpl "bufferPool\n*" --> "1" BufferPool
ByteBufferVendor.ByteBufferSharingInternalImpl "bufferType\n*" --> "1" BufferType
ByteBufferVendor .. ByteBuffer : derived\nassociation
@enduml |
ByteBuffers are not meant to be accessed concurrently. But our NioFilter classes, particularly, NioSslEngine manipulate ByteBuffers, and are themselves subject to concurrent access. As a result it's often necessary to protect ByteBuffers from concurrent access.
...
In the class diagram at the top of this page you'll see a dotted association between ByteBufferVendor and ByteBuffer labeled "derived association". That's meant to convey the fact that kind of the whole point of the vendor is that it mediates access to a ByteBuffer. In UML terms, there is a derived association between the two, even though you won't see an explicit (direct) object reference in the code.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
ByteBufferSharing WRONG() throws IOException { try (final ByteBufferSharing sharing = vendor.open()) { // +1 net reference count // access ByteBuffer through sharing reference here // NEVER DO THIS: you risk the reference count dropping to zero // before the caller can bind the reference value in its own // try-with-resources block return sharing } // +0 net reference count--buffer is potentially eligible // for return to pool before caller can access it! } |
...