I have a thread that invokes two separate threads. It passes in the same CompletableFuture
to both of those child threads. If .get()
was called in both of those threads at the exact same time, would I get any type of concurrency issues?
CompletableFuture
?.get()
?As a concrete example, in the following code, would it be possible that the two threads print a different value, assuming nothing changes the object returned by cfInput.get()
after cfInput
is completed?
public void mainClass(CompletableFuture<ObjA> cfInput){
class1.doAsync1(cfInput);
class2.doAsync2(cfInput);
}
@Async
public void doAsync1(CompletableFuture<ObjA> cfInput){
//logic
System.out.println(cfInput.get().getObjB().getBlah());
//logic
}
@Async
public void doAsync2(CompletableFuture<ObjA> cfInput){
//logic
System.out.println(cfInput.get().getObjB().getBlah());
//logic
}
public class ObjA{
private ObjB objB;
public ObjB getObjB();
public void setObjB();
}
public class ObjB{
private String blah;
public String getBlah();
public void setBlah();
}
CompletableFuture
is inherently thread-safeYou could simply assume this from the fact that this class is designed to be used in a multi-threaded context, however this is more clearly specified in the description of the java.util.concurrent
package:
Memory Consistency Properties
Chapter 17 of the Java Language Specification defines the happens-before relation on memory operations such as reads and writes of shared variables. The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation. […] The methods of all classes in
java.util.concurrent
and its subpackages extend these guarantees to higher-level synchronization. In particular:
- […]
- Actions taken by the asynchronous computation represented by a Future happen-before actions subsequent to the retrieval of the result via
Future.get()
in another thread.
So this implies that any write that is performed by a thread before it completes a future will be visible to any other thread that calls get()
on that future (i.e. it “happened-before”).
… nor are they “protected” by CompletableFuture
Even though CompletableFuture
itself is thread-safe, and provides some guarantees on the visibility of your writes, it does not make your objects thread-safe.
For instance, if you modify the object returned by CompletableFuture.get()
, those changes are not guaranteed to be visible to any other thread until you enter another happens-before relationship. You may thus need additional synchronization to enforce thread-safety on that object.