Home > Mobile >  Concurrent programming in Java with return values
Concurrent programming in Java with return values

Time:06-26

I have a problem with concurrent programming in Java. I am working on my bachelor thesis and I have to make several methods which will return me a String value. In the Futures TriggerMessageFututre and getMeterValuesFuture is a process running which takes between 1-5 seconds and returns a String Value when it's finished.

The problem is now that future.get() is blocking my main thread. I want to call the TriggerMessage and the getMeterValue methode in my main without blocking my main thread and get their answer as a return value when they are finished. I wasn't able to find a way to solve my problem, because either it was a solution without return value or it was a solution which blocked the thread.

private String TriggerMessage(String Messagetyp) throws InterruptedException, ExecutionException{
    Future<String> future = new communicator().TriggerMessageFuture(queue,centralSystem,Messagetyp);

    while(!future.isDone()) {
        System.out.println("[TriggerMessage]: Calculating... ");
        Thread.sleep(500);
    }

    String result = future.get(); //blocking
    return result;
}

private String getMeterValue(String key) throws Exception{
    Future<String> future = new communicator().getMeterValueFuture(queue,centralSystem,key);

    while(!future.isDone()) {
        System.out.println("[getMeterValue]: Calculating...");
        Thread.sleep(500);
    }

    String result = future.get(); //blocking
    return result;
}

CodePudding user response:

It depends on what main thread are you referring to, plus if you can use CompletableFutures instead of plain old Java Futures.

  1. Using the main(String[] args) thread

It's not possible to do it without any form of blocking. If you are not blocking on get, you'll have to block on a BlockingQueue implementation, otherwise the main thread just ends.

  1. Using the Swing Event Dispatch thread

You'd need to submit a continuation task which is not possible with Future.get from the outside. So either you include this submission inside the task Future has been created for, or switch to CompletableFuture

ExecutorService exec = ...

Future<?> future = exec.submit(() -> {
   var value = someCalculation();
   SwingUtilities.invokeLater(() -> {
       useValueOnEDT(value);
   });
});

or

CompletableFuture<ValueType> cf = ...

cf.whenComplete((value, error) -> {
    SwingUtilities.invokeLater(() -> {
        if (error != null) {
            handleErrorOnEdt(error);
        } else {
            useValueOnEDT(value);
        }
    });
});
  1. Android Main Thread

The idea is the same as with Swing, but you'll have to use a Handler

// given value
new Handler(Looper.getMainLooper()).post(() -> {
    useValueOnMainLooper(value);
});

CodePudding user response:

You can wrap the Future into a CompletableFuture like so

static <T> CompletableFuture<T> from(Future<T> future) {
    var delegate = new CompletableFuture<T>();

    CompletableFuture.runAsync(() -> {
        try {
            delegate.complete(future.get());
        } catch (Throwable e) {
            delegate.completeExceptionally(e);
        }
    });

    return delegate;
}

And then use that CompletableFuture to asynchronously handle the completion via its various then... and when... methods.

  • Related