Tobiq
Tobiq

Reputation: 2657

Wait for callback from other thread

First of all, I've decided to make my class blocking (to make it easier for the consumer to use - but maybe more tedious for me to write). As opposed to having the consumer define asynchronous callbacks. Is this a good design pattern? This way, a user can get expected behaviour, but implement their own multi-threading if they're dissatisfied with how long the thread's blocked for.

I've got a constructor that sets a final field in a class, based on the result of an async callback:

class Example {
    private final int x;

    Example(){
        asyncFunc(/* callback */ result -> x = result)
    }
}

This doesn't work, so I've used atomic references, and implemented a blocking loop, until the result it returned, like so:

class Example {
    private final int x;

    Example(){
        x = waitAsyncFunc();
    }

    private int waitAsyncFunc(){
        AtomicBoolean finished = new AtomicBoolean(false);
        AtomicReference<byte[]> result = new AtomicReference<>();
        asyncFunc(result -> {
            result .set(res);
            finished.set(true);
        });
        while (!finished.get()) { /* No op */ }
        return result.get();
    }

}

Is this a good way to block / retrieve the result?

Upvotes: 3

Views: 1933

Answers (2)

lugiorgi
lugiorgi

Reputation: 546

Instead of blocking the thread with a loop, you can use a CountDownLatch.

As taken from the docs (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

Your code would look something like:

private int waitAsyncFunc() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        AtomicReference<byte[]> result = new AtomicReference<>();
        asyncFunc(result -> {
            result.set(res);
            latch.countDown();
        });
        latch.await(); //You can even specify a timeout
        return result.get();
    }

Upvotes: 3

Holger
Holger

Reputation: 298539

The simplest solution would be

class Example {
    private final int x;

    Example() {
        CompletableFuture<Integer> f = new CompletableFuture();
        asyncFunc(f::complete);
        x = f.join();
    }
}

But consider the alternative of waiting for the asynchronous job’s completion before even constructing the Example instance.

Upvotes: 4

Related Questions