Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The framework leverages the try-with-resources syntax to deliver exclusive ByteBuffer access in lexical blocks. The ByteBufferSharing class provides a couple open() methods (one of which supports timeout). These methods return an AutoCloseable "resource", suitable for assignment in a try-with-resources variable declaration. The Java language guarantees that close() will be called on such a resource when the lexical block is left (either through normal program flow or exception). The framework leverages that close() call as a signal to release locks and reduce reference counts.

These are the key interfaces used by clients of the framework:

PlantUML
@startuml
class SomeApplicationClass {
}

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()
}

SomeApplicationClass "vendor" *-- ByteBufferVendor
ByteBufferVendor "sharing" *-- ByteBufferSharing
ByteBufferVendor .. ByteBuffer : derived\nassociation
@enduml

more

Internals

In the diagram SomeApplicationClass is a class outside the framework, that needs shared ByteBuffers. SomeApplication class has a field holding a ByteBufferVendor. The object referenced by that field is constructed by SomeApplicationClass and when that class is done with the ByteBuffer it calls ByteBufferVendor.destruct().

When SomeApplicationClass needs to access the ByteBuffer it calls ByteBufferVendor.open() as part of a try-with-resources variable declaration. Inside the scope of that try-with-resources block, the thread has exclusive access to the ByteBufferSharing object, and to its associated ByteBuffer.

The try-with-resources machinery works because ByteBufferSharing implements AutoCloseable. Within the scope of a try-with-resources block, client code accesses ByteBuffer functionality through the ByteBufferSharing interface:

Code Block
languagejava
firstline1
titleByteBufferSharing
linenumberstrue
ByteBuffer getBuffer()
ByteBuffer expandWriteBufferIfNeeded(int newCapacity)
ByteBuffer expandReadBufferIfNeeded(int newCapacity)

The first method, obviously, is used to get the ByteBuffer. In the context of try-with-resources, you have exclusive access to the ByteBuffer so you needn't worry about other threads preempting you.

The other two methods are for expanding the ByteBuffer.

In the next section we'll describe some framework internals.

Internals

The ByteBufferSharingInternalImpl class (a private, static internal class of ByteBufferVendor) is the main implementation of the "resource" class just mentioned.

The next class diagram (below) expands on the client view depicted in the first diagram. The dotted association between ByteBufferVendor and ByteBuffer is labeled "derived association". That's meant to convey the fact that 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.

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

The ByteBufferSharingInternalImpl class (a private, static internal class of ByteBufferVendor) is the main implementation of the "resource" class just mentioned. It implements AutoCloseable so it's usable as a resource in try-with-resources. It also implements a public interface, ByteBufferSharing, for use by clients within a try-with-resources block. It's this interface that a user of ByteBuffers will be most interested in:

Code Block
languagejava
firstline1
titleByteBufferSharing
linenumberstrue
ByteBuffer getBuffer()
ByteBuffer expandWriteBufferIfNeeded(int newCapacity)
ByteBuffer expandReadBufferIfNeeded(int newCapacity)

The first, obviously, is used to get the ByteBuffer. In the context of try-with-resources, you have exclusive access to the ByteBuffer so you needn't worry about other threads preempting you.

The other two methods are for expanding the ByteBuffer.

...

Following the Rules

A "resource" object returned from a ByteBufferSharing open() must be assigned in a try-with-resources variable declaration.

...