Noel De Martin
Noel De Martin

Reputation: 2857

How can I store a reference to an object that's being set in a different Thread?

I've come across this particular scenario many times, and I wonder what's the "clean" way of solving it. It all comes to this: how can I store a reference to an object that's being set in a different Thread?

Let me illustrate this with an example, imagine I have a class named Bar, and objects from this class are retrieved from this method:

public class BarBuilder {

    public static void buildNewBar(final BarListener listener) {
        // This could be an HTTP request or something that can only be done in a
        // different thread
        new Thread(new Runnable() {
            @Override
            public void run() {
                listener.onNewBar(new Bar());
            }
        }).start();
    }

}

The important part here is that buildNewBar() method has to be executed in another Thread, so instead of returning the value, it will communicate the result through a listener. This is quite common for operations that need HTTP requests or any sort of connection.

Now, my problem is if I need the value before continuing execution, how can I access to it? I can lock a thread with a semaphore until I have my value, but the storing of the value is what I don't have clear (If I declare a final variable, it cannot be set again). I solved it creating a new class which I named "Pointer", but I wonder why there isn't any built in java class to do this (I used Vector before, but it doesn't seem like a good solution either).

public Bar getBar() {
    final Pointer<Bar> barPointer = new Pointer<Bar>();
    final Semaphore semaphore = new Semaphore(0);

    BarBuilder.buildNewBar(new BarListener() {
        @Override
        public void onNewBar(Bar bar) {
            barPointer.set(bar);
            semaphore.release();
        }
    });
    semaphore.acquireUninterruptibly();

    // Now I have my value
    return barPointer.get();
}

public class Pointer<T> {
    T object;

    public void set(T object) {
        this.object = object;
    }

    public T get() {
        return object;
    }
}

Let's see if there is a better way of doing this supported by Java language, I have seen classes like Reference, but it seems like their purpose is something different and setters don't exist (they are read-only), so that doesn't solve my issues either.

Upvotes: 0

Views: 85

Answers (2)

jtahlborn
jtahlborn

Reputation: 53694

public Bar getBar() {
    final BarPointer barPointer = new BarPointer().

    BarBuilder.buildNewBar(barPointer);

    return barPointer.get();
}

public class BarPointer extends FutureTask<Bar> implements BarListener {
    @Override
    public void onNewBar(Bar bar) {
        set(bar);
    }
}

Upvotes: 2

Mackenzie
Mackenzie

Reputation: 1927

In order to eliminate the need to write a custom Pointer class, I would simply use AtomicReference.

Upvotes: 0

Related Questions