The happens-before principle is one of the most important principles in concurrent programming. Today we will discuss the happens-before principle in detail.

This article is from huawei cloud community “[High Concurrency] One second understand happens-Before principle”, by Glacier.

The happens-before principle is one of the most important things to learn in concurrent programming. Today we will talk about the happens-before principle in detail.

Before we formally introduce the happens-before principle, let’s look at a bit of code.

[Example 1]

class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() {if (v == true) {// what is the value of x? }}}Copy the code

The preceding examples are from: www.cs.umd.edu/~pugh/java/…

Here, suppose thread A executes writer() and writes v=true to memory as volatile; As volatile, thread B reads v from memory. If v is true, what is the value of x?

The intuitive value of x is 42, depending on the JDK version, and could be either 42 or 0 if the JDK version used is less than 1.5. If you’re using JDK 1.5 and above, the value of x is 42.

When you see this, you ask questions, right? Why is that? The answer is to introduce the happens-before principle into the Java memory model in JDK1.5.

Next, we use a case program to illustrate the happens-before principle in the Java memory model.

[Principle 1] Procedural order rules

In a thread, the previous action is happens-before any subsequent action, in code order.

For example, the program x=42 in [Example 1] executes before v=true. This rule is more consistent with single-threaded thinking: in the same thread, changes made to a variable in front of the program must be visible to subsequent operations.

【 Principle 2 】 Rules for volatile variables

A write to a volatile variable is happens-before a subsequent read to that variable.

That is, a write to a volatile variable occurs first after a read is performed on that variable. This is important for you to understand.

[Principle 3] Rules of transmission

If A Happens-Before B, and B Happens-Before C, then A Happens-Before C.

We combine [Principle 1], [Principle 2] and [Principle 3] to look at the [Example 1] program. At this point, we can draw the following conclusions:

(1) x = 42 happens-before write variable v = true, in accordance with [Principle 1] program order rule.

(2) Write variable v = true Before read variable v = true, in accordance with [Principle 2] volatile variable rule.

According to the transfer rule, we can draw the conclusion that x = 42 happens-before reads variable v=true.

That is, if thread B reads v=true, thread A’s x = 42 is visible to thread B. In other words, thread B has access to x=42.

In fact, the java.util.concurrent utility in Java version 1.5 relies on volatile semantics for visibility.

[Principle 4] Locking rules

The happens-before action to unlock a lock is later than the happens-before action to unlock the lock.

For example, the following code automatically locks a synchronized block before entering it and releases the lock after the block is executed.

【 Example 2 】

public class Test{ private int x = 0; Public void initX{synchronized(this){if(this.x < 10){this.x = 10; } // Automatic release lock}}Copy the code

This program can be understood as follows: assuming the value of x is 10, thread A changes the value of x to 10 after executing the synchronized block and releases the synchronized lock. When thread B enters the synchronized code block, it can obtain the write operation of thread A on x variable, that is, the value of x variable accessed by thread B is 10.

[Principle 5] Thread start rule

If thread A calls thread B’s start() method to start thread B, the start() operation is happens-before any operation in thread B.

We can also understand the thread start rule this way: after thread A starts thread B, thread B can see what thread A did before it started thread B.

Let’s look at the following code.

【 Example 3 】

ThreadB = new Thread(()->{threadB = new Thread()->{ The answer is 100}); Thread A changes the value of shared variable x to 100 x = 100 before starting thread B; // start threadB threadb.start ();Copy the code

The above code is A code snippet executed in thread A. According to the starting rule of thread [Principle 5], after thread A starts thread B, thread B can see the operation of thread A before starting thread B. The value of x variable accessed in thread B is 100.

Rule 6: Thread termination rule

Thread A waits for thread B to complete (it calls thread B’s join() method in thread A). When thread B completes (thread A returns from calling thread B’s join() method), thread A can access thread B’s operations on shared variables.

For example, the following operation is performed in thread A.

[Example 4]

ThreadB = new Thread(()-{// If threadB = new Thread()-{// If threadB = new Thread()-{// If threadB = new Thread()-{ }); Threadb.start (); // wait for threadB to complete threadb.join (); // The value of the access shared variable x is 100Copy the code

[Principle 7] Thread interrupt rule

The call to the threadinterrupt () method happens-before occurs when the interrupted thread’s code detects the occurrence of an interrupt event.

For example, the following program code. Change the value of the shared variable X to 100 before interrupting thread B in thread A, so that when thread B detects an interrupt event, the value of the x variable accessed is 100.

[Example 5]

Private int x = 0; private int x = 0; Thread threadB = new Thread(()->{// Thread B checks whether it is interrupted if (thread.currentthread ().isinterrupted ()){// if Thread B isInterrupted, X is 100 system.out.println (X); }}); Threadb.start (); // Change the value of shared variable X in thread A to 100 X = 100; // interrupt threadB threadb.interrupt (); }Copy the code

[Principle 8] Object termination principle

An object’s initialization completes happens-before the start of its Finalize () method.

For example, the following program code.

[Example 6]

Public class TestThread {public TestThread(){system.out.println (" constructor "); {Override protected void finalize() throws Throwable {system.out.println (" object destruction "); } public static void main(String[] args){ new TestThread(); System.gc(); }}Copy the code

The result is as follows.

Constructor object destructionCopy the code

Click to follow, the first time to learn about Huawei cloud fresh technology ~