I am trying to create a simple example with async CompletableFuture's but I'm seeing some weird behaviour. The idea is that I kick off 2 async futures, one activates a boolean flag after a set time and the other polls that flag to release the value once thread 1 has changed that flag. Here's my code:
package completablefutures;
import java.util.concurrent.CompletableFuture;
public class CFMain throws InterruptedException {
public static void main(String... args) {
CF cf = new CF();
CompletableFuture.supplyAsync(cf::getCompletable).thenRun(() -> System.out.println("Post-future action"));
CompletableFuture.supplyAsync(cf::doSleep);
Thread.sleep(10000);
}
}
And the CF class:
package completablefutures;
public class CF {
private boolean valueIsSafe = false;
public boolean getCompletable() {
System.out.println("Fetching completable");
while(true) {
if(this.valueIsSafe) {
System.out.println("Completable fetched");
return true;
}
}
}
public boolean doSleep() {
System.out.println("Started sleeping");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.valueIsSafe = true;
System.out.println("Finished sleeping");
return true;
}
}
When I let the program run it's course, it prints this:
Fetching completable
Started sleeping
Finished sleeping
Process finished with exit code 0
i.e. the future never completes in the 10s allocated. So what's going on here?
You are accessing the valueIsSafe
from multiple threads, you must define this variable as volatile
.
private volatile boolean valueIsSafe = false;
Using the volatile keyword will prevent threads from caching this value and force them to read the raw memory on every access.