DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • A Systematic Approach for Java Software Upgrades
  • Building a Simple RAG Application With Java and Quarkus
  • Dust Actors and Large Language Models: An Application
  • Five Java Developer Must-Haves for Ultra-Fast Startup Solutions

Trending

  • Scalable, Resilient Data Orchestration: The Power of Intelligent Systems
  • It’s Not About Control — It’s About Collaboration Between Architecture and Security
  • The Modern Data Stack Is Overrated — Here’s What Works
  • Understanding Java Signals
  1. DZone
  2. Coding
  3. Java
  4. Happens-Before In Java Or How To Write a Thread-Safe Application

Happens-Before In Java Or How To Write a Thread-Safe Application

This article explains the notion of happens-before in Java, including ways to install it, what guarantee it gives, advantages it brings, and how to use it.

By 
Dmitry Egorov user avatar
Dmitry Egorov
DZone Core CORE ·
Jul. 26, 22 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
10.6K Views

Join the DZone community and get the full member experience.

Join For Free

Multithreading is the most complex part of Java. Happens-before is a relation that gives a guarantee of allowing the writing of predictable code in multithreading a reality. Such code is also known as thread-safe code. Unfortunately, Oracle Java documentation about this notion is hard to read. So in this article, I'll mainly explain what happens-before is in human language and provide detailed examples.

Google screenshots

Happens-Before Solves the Main Multithreading Problem

Before we start learning the happens-before notion, we have to understand the reason for creating it. Once multithreading comes to the scene, your code might become inconsistent because shared objects between threads might have different and unpredictable values. Let's review a simple example. In that example, we will update values in one thread and read and print them in another.

Update values in one thread and read and print them in another

Expected Behavior (False Expectations)

Now let's think about what values we might see in the second thread while printing.  Depending on progress in the first thread, we might expect 3 situations: 

  1. X and y are not initialized, so 0 and 0 will be printed.
  2. X is set and y is not set yet; then, 1 and 0 will be printed.
  3. X and y are set; then, 1 and 1 will be printed.

A, B, and C case

 Now let's run the program a million times and see what values have been printed. 

Printed values after running a million times

Among a million prints, there were only 3 different options printed (with my hardware, Windows OS, and my JDK). For some reason, the B case never appeared because it's not as confusing as an 0,1 pair, which looks impossible. The only thing we have to learn here is that results are unpredictable. 

Why Shared Memory Might Be Inconsistent

This is a pretty big topic and it's not the main subject of this article, so I will just briefly introduce the most known reasons.  

Reordering or JVM Optimizations

JVM can change the order of the instructions which won't make any significant changes in the program. For example, it might change the order of variable initialization.

Change the order of variable initialization

CPU Memory Cache

Each thread can be executed in a separated CPU. CPU has its own cache with different variables copied. When one thread updates the value in the CPU, another thread will still have an outdated value. We can illustrate it like this:

When one thread updates the value in the CPU, another thread will still have an outdated value

Both threads read data from shared RAM memory after processing its data with resynchronization. By default, nothing forces the CPU to update the shared RAM memory value.

What Is Actually Important: Thread-Safe Code

Everything explained earlier is only valuable for passing interviews; but in practice, all developers need is a way to predictably and consistently code in a multithreading reality, also known as thread-safe code. Fortunately, Java offers ways to write such code.

Happens-Before Gives a Guarantee of Visibility of Same Fields in Different ThreadsHappens-before graphic

The happens-before relationship is described in Oracle Documentation, Chapter 17.4.5. If between two threads, we installed the happens-before relation, then the second (ending thread) will see all changes that happened in the first thread. Therefore, the second thread execution will be similar to a single thread application.

Install Happens-Before Relationship: Making Fields Visible (Using a Volatile Keyword)

The first way to install the happens-before relation is to mark a shared variable with a volatile keyword. If a variable is volatile, then the happens-before relation will be installed between every write and subsequent reads.

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

This means that:

  • Once Y is updated in the first thread, it will be visible in the second thread.
  • When Y became visible in the second thread, all fields are set before Y.

Considering this, we have to make the next changes in order to have x and y consistent:

  • Make Y volatile.
  • Make X read after Y in the second thread.
  • Check that Y is set to 1.

bean.Y is read at first place

Considering all the changes, we rewrite our code in this way next:

Code rewrite

This might be a bit complicated. One thing you have to pay attention to is that the blue portal means that the happens-before relation is installed (starting point) and the yellow portal means that the happens-before relation is completed (and all data "passed" through is received with the latest, up-to-date state).

Install Happens-Before Relationship: Making Ordered Access to Fields (Using Synchronized Monitor)

Java provides a way to organize ordered access to the instructions known as a Java monitor. I have described what it is and how it works in a set of three articles:

  • Multithreading Java and Interviews Part 2: Mutex, the Java Monitor Model

This subject is pretty complex. I also recommend reading these articles:

  • What is a Monitor in Computer Science?
  • Guide to the Synchronized Keyword in Java

The happens-before relationship is installed between any lock acquire and lock release. So, if we rewrite our code using locks, we also have a happens-before guarantee:

Code rewrite using locks

As you can see, both fields are not volatile; but when the first thread updates the value and releases the lock, then in the second thread when the lock is acquired, the value also gets updated due to the happened-before relation. This rule applied to all locks from java.util.concurrent that use a Java monitor under the hood.  

Install Happens-Before Relationship: Thread Start and Join

This might be the easiest case compared to the previous two. Java specification says:  

- A call to start() on a thread happens-before any actions in the started thread.

- All actions in a thread happen-before any other thread successfully returns from a join() on that thread.

When the thread starts, it sees the correct state of shared variables of the parent thread. This is backward when the parent thread is released after join(): it receives the latest state of the child thread.  

Let's rewrite our example and illustrate how bean data is passed to the child thread when we call the start() method:

How bean data is passed to the child thread when we call the start() method

The example explains that values set in the main thread are successfully passed to the child thread due to the installation of the happens-before relation, and thanks to start() method.

Now let's illustrate the same logic, but when data is passed from the children to parent on join() method:

When data is passed from the children to parent on join() method

In this example, we pass data from the child thread to the main awaiting thread. Once a child thread ends its run and releases join, then values are passed correctly due to the existence of the happens-before relationship.

Are Examples Production-Ready and Recommended To Use?

Synchronization without volatile cartoon

No, no, no! The examples that I provided served only one purpose: to explain what happens-before is, and how it works. In practice, you can't be too careful in a multithreading environment. To better avoid things I have shown: 

  • In the first case with visibility (volatile keyword), I marked only one field as volatile. The code will work as expected; but in practice, you can change the order of reading and the "broken" happens-before relationship. 
  • In the case of the synchronization monitor, I didn't mark fields as volatile because it's not necessary. Don't do this. Keep fields volatile even if they are changed inside the lock.

Also, it is worth mentioning that in the first example (with volatile), I didn't mention when what happens-before relation is not enough when you take care of consistency. Volatile keywords give you safe reads, but not simultaneous writes (leads to race conditions). This subject is outside of this article.

Constructive Discussions Are Welcome

The happens-before subject is one of the most complex subjects, and often are part of senior Java interviews. If you don't agree with something or you want to add something related, I'm glad to have a constructive discussion in the comments. Thanks for reading.  

application Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • A Systematic Approach for Java Software Upgrades
  • Building a Simple RAG Application With Java and Quarkus
  • Dust Actors and Large Language Models: An Application
  • Five Java Developer Must-Haves for Ultra-Fast Startup Solutions

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!