My question is related to this question, which already has an answer:
yes, there is a happens-before relationship imposed between actions of the thread calling
invokeLater/invokeAndWaitand actions on the EDT of the runnable thereby submitted.
My question is a bit more general: Is it even possible to implement a method, such as invokeAndWait, such that it works properly, but not imposing a happens-before relationship? By the method working properly I mean the following:
- The submitted
Runnableis guaranteed to be executed exactly once. - The submitted
Runnableis executed on a specific thread. - The method waits until the execution of the submitted
Runnablehas finished. - The method is guaranteed to return after the execution of the submitted
Runnablehas finished.
To me there seems to be no way to implement this without imposing a happens-before relationship, or am I wrong? If so, please include an example implementation, which proves this.
The most difficult requirement here is:
Using a non-
volatile(Plain) field for transfering the work task from the submitter to the executor would not create a happens-before relationship, but would also not guarantee that the executor sees the task at all or in a finite amount of time. The compiler would be able to optimize away assignments to that field, or during runtime the executor thread might only read the value from its cache instead of from main memory.So for code using Java 8 or lower, I would say the answer is "No, such an
invokeAndWaitmethod is not possible" (except maybe using native code).However, Java 9 added the memory mode Opaque. The page "Using JDK 9 Memory Order Modes" by Doug Lea, the author of JEP 193 (which added this functionality), describes this in great detail. Most importantly Opaque mode is weaker than
volatilebut provides still the following guarantee:When designing such an
invokeAndWaitmethod without happens-before relationship you also have to consider that an action before starting a thread happens-before the first action in that thread (JLS §17.4.4). So the worker thread must be started before the action is constructed.Additionally the "
finalfield semantics" (JLS §17.15.1) have to be considered. When the caller ofinvokeAndWaitcreates theRunnablein the form of a lambda expression, then the capturing of variables by that lambda has (to my understanding) implicitfinalfield semantics.Proving or disproving thread-safety or happens-before relationships using examples is difficult, if not impossible, due to being hardware and timing dependent. However, tools like jcstress can help with this.
Below is a (simplified) potential implementation for an
invokeAndWaitwithout happens-before relationship. Note that I am not completely familiar with the Java Memory Model so there might be errors in the code.