Proper way to wait for a lambda to complete

ekjcfn3902039 :

I came across the following snippet of code:

AmqpConnection connection;
AmqpClient client = AmqpClient.create(someOptions);

client.connect(ar -> {
  if (ar.failed()) {
    System.out.println("Connection failed.");
  } else {
    System.out.println("Connection succeeded");
    connection = ar.result();
  }
});

// Wait for connection to succeed before moving on...
connection.doSomething() //etc...

I would like to use it but there needs to be a blocking mechanism so connection is not null. I do not want to move connection.doSomething() inside the lambda. What is the proper way to block in that scenario? A while loop with a timer? A Future/Callable? Something else?

orirab :

Future is one great way, however does connect return one?

You said you prefer not to, but another option would be to add it all to the lambda itself - if you're waiting anyway, why not do it together?

I think the way you have it set now is not a good one, as lambdas are not supposed to affect variables outside their body (I believe you'll receive a compile error on this).

There are some more ways using java.util.concurrent, but I think these 2 are the best.


EDIT

Following discussion in the comments, and clarification that the connection is thread safe, you can split to ConnectionUtil that creates the connection (once-only), and ConnectionUsage as a usage example:

public class ConnectionUtil {

    private static AmqpConnection connection;

    private static Lock lock = new ReentrantLock();

    public static AmqpConnection getConnection() {
        if (connection == null) {
            lock.lock();
            if (connection == null) {
                AmqpClient client = AmqpClient.create(someOptions);
                client.connect(ar -> {
                    if (ar.failed()) {
                        System.out.println("Connection failed.");
                    } else {
                        System.out.println("Connection succeeded");
                        connection = ar.result();
                    }
                });
            }
            lock.unlock();
        }
        return connection;
    }

    public static <T> T doWithConnection(Function<AmqpConnection, T> function) {
        return function.apply(getConnection());
    }
}

For usage, you have 2 options - if it is okay to pass the AmqpConnection around, you can call getConnection, and if not have your lambda ready and pass it to doWithConnection:

public class ConnectionUsage {

    public static void main(String[] args) {
        // you can get the connection and do stuff
        AmqpConnection connection = ConnectionUtil.getConnection();


        // you can call the util and let him do stuff
        Function<AmqpConnection, Void> func = amqpConnection -> {
            // do stuff
            return null;
        };
        ConnectionUtil.doWithConnection(func);
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=126542&siteId=1