Graphical Java multi-thread notes: tutorials.jenkov.com/java-concur…

The Java Memory Model (JMM) defines: how and when different threads can see values written to shared variables by other threads, and how to synchronize access to shared variables when necessary.

Where objects are stored in the Java heap and stack:

Java Memory model vs. Hardware model:

Threads read data from main memory into the CPU buffer, and when data is placed in different locations, there are two problems: visibility and static conditions

A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.

The synchronized keyword can be used to mark four different types of blocks:

  1. Instance methods -> on the instance (object) owning the method
  2. Static methods -> on the class object of the class belongs to…
  3. Code blocks inside instance methods
  4. Code blocks inside static methods

Synchronized Instance methods

Static method synchronization:

Code block synchronization:

Using jStack, only one thread is allowed to access the same monitor object:

The synchronization of the instance method plus the synchronization of the code block this is still for the same instance object:

Custom monitor objects:

Locking of the same instance object:

Locking different instance objects:

Volatile keyword guarantees visibility of changes to variables across threads.

every read of a volatile variable will be


Read from the computer’s main memory,


and not from the CPU cache.

every write to a volatile variable will be

written to main memory,

and not just to the CPU cache.

If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B after it has read the volatile variable.

The reading and writing instructions of volatile variables cannot be reordered by the JVM. Instructions before and after can be reordered, but the volatile read or write cannot be mixed with these instructions. Whatever instructions follow a read or write of a volatile variable are guaranteed to happen after the read or write.

Volatile variables do not guarantee transactions:

Volatile variables still have race conditions:

Volatile variables disallow reordering:

If a variable is not guaranteed to be written to main memory after a volatile variable is updated:

To ensure visibility, it is not necessary to define each variable as volatile:

Volatile variables are memory barriers that allow instructions before and after to be reordered:

Example of a local thread:

The figure below does not use local threads, and the figure below does:

Thread semaphore implementation — busy waiting:

Alternatively, volatile variables can be used:

Examples of wait and notify:

Examples of notify and notifyAll:

If the waiting thread is awakened unexpectedly, we need to use the while loop to continue to determine whether the notify thread is awakened:

Wake up all threads at once, or one at a time:

Using strings as monitor locks between different threads wakes up other threads:

Signals are not shared between different threads, and the waiting thread continues to wait after being awakened:

Examples of wait and wake up for different threads: