Brendon Cheung
Brendon Cheung

Reputation: 1035

How to make Java runnable call a callback from the main thread, and not the background thread?

I was doing some thought experiment and here is my MyRunnable class:

class MyRunnable implements Runnable {

    private final Integer mNumber;
    private final CompleteHandler<Integer> mCallback;

    public MyRunnable(Integer i, CompleteHandler<Integer> ch) {
        mNumber = i;
        mCallback = ch;
    }

    public void run() {

        int sum = 0;

        for (int i = 1; i <= mNumber; i++) {
            sum += i;
        }
        mCallback.onFinished(sum);
    }
}

This will be executed by a background thread which I create on the main thread, under the execute() method

public class Demo implements CompleteHandler<Integer>{

    public static void main(String[] args) {
        Demo d = new Demo();
        d.execute();
    }

    @Override
    public void onFinished(Integer i) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName);    // thread-0
    }

    public void execute() {
        MyRunnable mr = new MyRunnable(10, this);
        Thread t = new Thread(mr);
        t.start();
    }
}

As you can see, the MyRunnable calls onFinished() when the task is finished. Is there any way I can have the background thread to call this on the main thread? I know I can do similar thing with callables, but right now I want to know if this is possible with runnables,

thank you

Upvotes: 1

Views: 958

Answers (1)

Solomon Slow
Solomon Slow

Reputation: 27115

Johannes: Take a look at CompletableFuture...

Brendon: I'm more interested in seeing how it work on code

Here's a simplistic implementation that ignores the issue of exceptions. (Pardon me if it's not actually valid Java code.)

class CompletableFuture<ValueType> {
    private Object lock = new Object();
    private boolean is_completed = false;
    private ValueType completed_value;

    public synchronized void complete(ValueType v) {
        completed_value = v;
        is_completed = true;
        notifyAll();
    }

    public synchronized ValueType await() {
         while (! is_completed) {
              wait();
         }
         return completed_value;
    }
}

The idea is, the client thread creates a CompletableFuture instance, cf, and somehow passes it to the server thread, possibly along with other args that tell the server thread what to do. Then the client thread goes off to do other, unrelated things.

Meanwhile, the server thread does its thing, eventually produces a result, r, and then it calls cf.complete(r).

At some point, the client thread finishes doing whatever else it was doing, and now it needs the result, so it calls cf.await(). Either one of two things happen at that point:

  1. The server already has set the is_completed flag, in which case, the client immediately gets the result, OR
  2. The server has not yet finished, so the client goes in to the wait() loop to wait for it.

When you're looking at application code, you usually never see the part where the client thread creates the Future object or passes it to the other thread. That usually is all taken care of inside the library call when the client submits a task to a thread pool.

Upvotes: 1

Related Questions