T
- type of the managed referencepublic interface Managed<T>
This utility class guarantees that the underlying reference has been initialized and that the block of code using it will never operate on an invalid reference.
An invalid reference is an object that has been freed or destructed before it is being used. An example would be a database connection that has been closed, any subsequent actions on it is very likely to cause an exception to be thrown. By wrapping the connection in a managed reference, any block of code using the reference prevents it from being deconstructed until it is no longer being used.
Since we cannot rely on the garbage collector being invoked in a timely fashion, the borrowed
references has to be manually released. Fortunately, there are some helpers to ease this like
doto(Function)
, the try-with-resources pattern on a Borrowed
reference, and the
Borrowed.release()
method.
This pattern is useful if you have a block of code returning a stage. It guarantees that the code is executed in a safe fashion, that will release the reference if it throws an exception. After it has successfully returned a stage, the borrowed reference will be released when this stage is completed:
final Managed<Database> m;
final Stage<Integer> stage = m.doto(db -> {
// do something with database
return db.count();
});
The following is an example using try-with-resource:
final Managed<T> m = ...;
try (final Borrowed<T> b = m.borrow()) {
final T value = b.get();
// do something with 'value'.
}
Finally, this is how you manually borrow and release the reference after use:
final Managed<T> m = ...;
final Managed.Borrowed<T> b = m.borrow();
try {
final T value = b.get();
// do something with 'value'.
} finally {
b.release();
}
Managed references are prime candidates for leaking references. This is caused by application
code not having a 1:1 correspondence between each borrow()
and
Borrowed.release()
call.
To aid troubleshooting, Borrowed
references have implemented the
Object.finalize()
that provides instrumentation through
Caller.referenceLeaked(Object, StackTraceElement[])
if the borrowed reference is garbage
collected before it has been released. Stack traces are only captured if the system property
defined by CAPTURE_STACK
is set to yes
.
Additionally, tracing for each managed reference can be enabled by setting the system property
defined by TRACING
to yes
. This causes the managed reference's
Object.toString()
to contain detailed information about every borrowed reference that has
currently been acquired. Like the following example:
Modifier and Type | Field and Description |
---|---|
static String |
CAPTURE_STACK
System property that if set to 'yes', will cause stacks to be captured by borrowed
references.
|
static String |
TRACING
System property that if set to 'yes', will cause the managed references to be traced.
|
Modifier and Type | Method and Description |
---|---|
Borrowed<T> |
borrow()
Borrow the underlying reference.
|
<U> Stage<U> |
doto(Function<? super T,? extends Stage<U>> action)
Borrow a reference and execute the given action.
|
boolean |
isReady()
If managed reference is started, but not stopping or stopped.
|
Stage<Void> |
start()
Start the managed reference.
|
Stage<Void> |
stop()
Stop the underlying managed reference.
|
static final String TRACING
static final String CAPTURE_STACK
This will cause managed references to be more memory intensive.
Stage<Void> start()
Stage<Void> stop()
If called multiple times will only A stop call will do the following (in order):
Borrowed<T> borrow()
This reference must be explicitly released, otherwise the application could leak
reference which will cause stop()
to misbehave
<U> Stage<U> doto(Function<? super T,? extends Stage<U>> action)
The reference will be released when the action's stage is finished:
final Managed<Database> m = ...;
return m.doto(db -> {
return db.query(...);
});
U
- the type of the return value from the actionaction
- The action to perform on the borrowed reference.boolean isReady()
Should only be used for diagnostical purposes. Code using references should utilize
stages returned by methods like start()
and stop()
to know when there
reference is ready.
true
if the underlying reference is constructed and available to be borrowedCopyright © 2017. All rights reserved.