tmn
tmn

Reputation: 11569

Is this a reference escape to a partially constructed object?

I want to run a CompletableFuture property on a given class. If i have initialized like so, would that be dangerous and possibly create a partially constructed object?

public class MyClass { 

    public final CompletableFuture<BigDecimal> myExpensiveVal = CompletableFuture.supplyASync(() -> calculateExpensiveMethod(this));

//...
}

Upvotes: 0

Views: 77

Answers (1)

Holger
Holger

Reputation: 298479

CompletableFuture.supplyASync sends the provided Supplier to another thread and, of course, if this supplier has any reference to your instance under construction, it is a leakage of this which makes an incomplete object instance visible to other threads and even voids any final publication guaranty.

In this special case it’s so obvious that you can spot this escaping reproducibly:

public class EscapingThis {

    public final CompletableFuture<BigDecimal> myExpensiveVal
                = CompletableFuture.supplyAsync(() -> calculateExpensiveMethod(this));
    final int fourtyTwo;

    public EscapingThis() {
        System.out.println(Thread.currentThread()+" starts creating "+this);
        try {
            myExpensiveVal.get();
        } catch (InterruptedException|ExecutionException ex) {
            Logger.getLogger("EscapingThis").log(Level.SEVERE, null, ex);
        }
        System.out.println("still incomplete");
        fourtyTwo=42;
        System.out.println("leaving constructor");
    }

    static BigDecimal calculateExpensiveMethod(EscapingThis instance) {
        System.out.println(Thread.currentThread()
                                 +" says: hello incomplete instance "+instance);
        System.out.println("fourtyTwo = "+instance.fourtyTwo);
        return BigDecimal.ONE;
    }
    public static void main(String... arg) {
        new EscapingThis();
    }
}

Here you will see hello incomplete instance EscapingThis@1a9515 and fourtyTwo = 0 before still incomplete and leaving constructor for sure. But you might even see the Thread[main,5,main] starts creating … message after the hello incomplete … message as the timing is undefined.

Note that if calculateExpensiveMethod is an instance method, it doesn’t need the this parameter to let the instance leak. The implied reference to this on which the instance method will be invoked is also a leaking reference.

Upvotes: 1

Related Questions