3.the Happens-Before Relationship and Model - Java Multithreading For Senior Engineering Interviews
3.the Happens-Before Relationship and Model - Java Multithreading For Senior Engineering Interviews
• Total order
• Partial order
• Actions
• Synchronization order
• Sequential consistency
• Example 2
Total order#
You are already familiar with total ordering, the sequence of natural
numbers i.e. 1, 2, 3 4, … is a total ordering. Each element is either greater or
smaller than any other element in the set of natural numbers (Totality). If 2
< 4 and 4 < 7 then we know that 2 < 7 necessarily (Transitivity) And finally
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 1/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
< 4 and 4 < 7 then we know that 2 < 7 necessarily (Transitivity). And finally
if 3 < 5 then 5 can’t be less than 3 (Asymmetry).
Partial order#
Elements of a set will exhibit partial ordering when they possess transitivity
and asymmetry but not totality. As an example think about your family tree.
Your father is your ancestor, your grandfather is your father's ancestor. By
transitivity, your grandfather is also your ancestor. However, your father or
grandfather aren't ancestors of your mother and in a sense they are
incomparable.
Actions#
A program consists of actions which can be any of:
1. reads or writes
The last three actions in the above list are categorized as synchronization
actions.
Synchronization order#
Each execution of a program has a synchronization order. A synchronization
order is a total order over all of the synchronization actions of an execution.
In terms of synchronization order a data race is defined by JSR-133 as:
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 2/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
Sequential consistency#
Sequential consistency says that all actions within a program are atomic and
follow a total order, which matches the program order. A program that has
no data races will exhibit sequential consistency across all its runs.
However, sequential consistency doesn’t imply program correctness. Groups
of operations that need to be executed atomically may not execute as such
giving rise to errors.
The sequential memory model is too restrictive and doesn’t allow for many
of the compiler and hardware optimizations. Quoting JSR-133:
When a program contains two conflicting accesses that are not ordered by a
happens-before relationship, it is said to contain a data race. A correctly
synchronized program is one that has
no data races. Furthermore, if a
program is correctly synchronized, then all executions of the program will
appear to be sequentially consistent.
Example 1#
Informally, we can summarize the above theoretical discussion as actions
upon shared data in two threads need to have a happens-before relationship
established among them. Without a happens-before relationship the
conflicting access to the shared data can result in concurrency bugs.
Consider the pseudocode for two methods, each executed by a distinct
thread below:
void method1() {
x = 1;
lock monitor;
y = 5;
unlock monitor;
void method2(){
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 4/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
(){
lock monitor;
r1 = y;
unlock monitor;
r2 = x;
Thread 1 Thread 2
lock monitor r1 = y
unlock monitor r2 = x
1. x=1
2. lock monitor
3. y=5
4. unlock monitor
5. lock monitor
6. r1 = y
7. unlock monitor
8. r2 = x
In contrast, let’s examine the scenario when thread2 acquires the lock on the
monitor first.
1. lock monitor
2. r1 = y
3. unlock monitor
4. r2 = x
5. x=1
6. lock monitor
7. y=5
8. unlock monitor
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 7/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
1. lock monitor
2. r1 = y
3. unlock monitor
4. x=1
5. r2 = x
6. lock monitor
7. y=5
8. unlock monitor
As you can see we have two valid permutations of executions when the
monitor is first locked by thread2, that may result in different values for x .
The reason for this error is that we have failed to establish a happens-before
relationship between two conflicting accesses of the same variable in two
different threads.
Establishing happens-before
relationship#
To make sure that the changes done by one thread to shared data are visible
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 8/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
To make sure that the changes done by one thread to shared data are visible
immediately to the next thread accessing those same variables, we must
Example 2#
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 10/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
If two fields X and Y are being assigned but don't depend on each other,
then the compiler is free to reorder them
Processors may execute instructions out of order under some
circumstances
Note that all these reorderings may happen behind the scenes in a single-
threaded program but the program sees no ill-effects of these reorderings as
the JMM guarantees that the outcome of the program would be the same as
if these reorderings never happened.
However, when multiple threads are involved then these reorderings take
on an altogether different meaning. Without proper synchronization, these
same optimizations can wreak havoc and program output would be
unpredictable.
public class ReorderingExample {
int x = 3;
int y = 7;
int a = 4;
int b = 9;
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 11/15
9/17/22, 10:12 AM
; The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
Object lock1 = new Object();
Object lock2 = new Object();
public void writerThread() {
// BLOCK#1
// The statements in block#1 and block#2 aren't dependent
// on eachother and the two blocks can be reordered by the
// compiler
x = a;
// BLOCK#2
// These two writes within block#2 can't be reordered, as
// they are dependent on eachother. Though this block can
// be ordered before block#1
y += y;
y *= y;
// BLOCK#3
// Because this block uses x and y, it can't be placed before
// the assignments to the two variables, i.e. block#1 and block#
2
synchronized (lock1) {
x *= x;
y *= y;
}
// BLOCK#4
// Since this block is also not dependent on block#3, it can be
// placed before block#3 or block#2. But it can't be placed befo
re
// block#1, as that would assign a different value to x
synchronized (lock2) {
a *= a;
b *= b;
}
}
Now note that even though all this reordering magic can happen in the
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 12/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
background but the notion of program order is still maintained i.e. the final
One can see that there's no partial ordering between block#1 and block#2
but there's a partial ordering between block#1 and block#3 where block#3
must come after block#1.
The reordering antics are harmless in case of a single threaded program but
program outputs quickly go awry when we introduce another thread that
shares the data that is being read or written to in the writerThread method.
Consider the addition of the following method to the previous class.
public void readerThread() {
a *= 10;
// BLOCK#4
// Moved out to readerThread() method from writerThread() method
synchronized (lock2) {
a *= a;
b *= b;
}
}
Note we moved out block#4 into the new method readerThread() . Say if the
readerThread runs to completion, it is possible for the writerThread to never
see the updated value of the variable a as it may never have been flushed
out to the main memory, where the writerThread would attempt to read
from. There's no happens before relationship between the two code snippets
executed in two different threads!
Don’t confuse happens-before to mean that one thread executes before the
other. All it means is that when readerThread releases the monitor, up until
that point, whatever shared variables it has manipulated will have their
latest values visible to the writerThread as soon as the writerThread
acquires the same monitor. If the writerThread acquires a different monitor
then there’s no happens-before relationship and it may or may not see the
latest values for the shared variables.
Back Next
Mark as Completed
Report an Issue
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 14/15
9/17/22, 10:12 AM The happens-before Relationship and Model - Java Multithreading for Senior Engineering Interviews
https://www.educative.io/courses/java-multithreading-for-senior-engineering-interviews/B8ngJnrBNoo 15/15