HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Disposable resource: lazy allocation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
disposableallocationlazyresource

Problem

Background

I'm writing a wrapper for a significant portion of a native library in Java. The native objects my classes are wrapping are giving me some headaches in terms of design.

I'm not a fan of the two-step initialization idiom but I've resigned myself to use it if the native object has a lot of configuration options followed by a rather complex and error-prone initialization.

The real issue is that I still have some constructors that throw exceptions after native resources have been allocated, though I'm able to avoid it in most cases. All classes wrapping native resources implement the Disposable interface.

public interface Disposable extends AutoCloseable
{
   boolean isClosed();

   @Override
   void close();
}


The close method is always written in the most safest way, making no assumptions about the state of the object. Okay, so I can call it from the constructor... that is unless there are subclasses that override this method.

Code

So I've been thinking about an elegant solution to solve these problems. I've decided to upgrade the allocation and deallocation of native objects to full object status.

public interface Resource extends Disposable
{
    T get();
}


These Resource objects are supposed to be pushed onto a stack that is shared with every class in the hierarchy so there is no longer a need to override the close method of a base class.

I have an abstract implementation that lazily allocates the native object once and returns it. I cannot use the double checked locking idiom to do this because I'm dealing with three states.

Either the native object hasn't been allocated, either it has, or it has been deallocated. If it has been deallocated, I don't want the possibility that it may accidentally be reallocated.

```
public abstract class AbstractResource implements Resource
{
private enum State
{
INITIAL,
ALLOCATED,
DISPOSED
}

private final AtomicReference refState;
priva

Solution

I'm not a fan of the two-step initialization idiom but I've resigned myself to use it if the native object has a lot of configuration options followed by a rather complex and error-prone initialization.

The real issue is that I still have some constructors that throw exceptions after native resources have been allocated, though I'm able to avoid it in most cases.

That's a suspicious set of problems to have; too bad you didn't ask for a review of that code. Off the top of my head, however, I've generally found that "a lot of configuration options" can usually be managed by a builder, and that trivial constructors seldom throw -- dependency injection pushes the exception risk outside of the constructor, where you can usually manage things more easily.

@Override
public void close()


If you aren't intending to let people create sub classes that circumvent the state machine, you might make these methods final.

protected abstract T allocate();
protected abstract void release(final T resource);


These methods don't belong here. The rest of your class is about lifecycle management; these are about resource management. You've mixed the concern about coordinating the life cycle with your concern for creation.

interface ResourceFactory {
    void T allocate();
    void release(T resource);
}


Then, in your lifecycle management, defer the work to the factory.

@Override
public void close() 
{
    if (this.refState.getAndSet(State.DISPOSED) == State.ALLOCATED)
        this.factory.release(this.resource);
}


10 out of 10 for making the state machine explicit. I suspect that you should make State.ALLOCATING and State.DISPOSING explicit. You might also want to look into Stateless4j; trivial state machines often grow in complexity.

Code Snippets

@Override
public void close()
protected abstract T allocate();
protected abstract void release(final T resource);
interface ResourceFactory<T> {
    void T allocate();
    void release(T resource);
}
@Override
public void close() 
{
    if (this.refState.getAndSet(State.DISPOSED) == State.ALLOCATED)
        this.factory.release(this.resource);
}

Context

StackExchange Code Review Q#110975, answer score: 2

Revisions (0)

No revisions yet.