61-What is the happens-before rule?

What is the happens-before relationship

The Happens-before relationship is used to describe issues related to visibility: if the first operation happens-before and the second operation (it can also be described as the happens-before relationship between the first operation and the second operation) , Then we say that the first operation must be visible to the second operation, that is, when the second operation is executed, it must be guaranteed to see the results of the first operation.

Examples that do not have a happens-before relationship

Let us first give an example that does not have a happens-before relationship to further understand what the happens-before relationship wants to express from a macro perspective. Let's take a look at the following code:

public class Visibility {
    
    
    int x = 0;
    public void write() {
    
    
        x = 1;
    }
    public void read() {
    
    
        int y = x;
    }
}

The code is very simple, there is an int x variable in the class, the initial value is 0, and the function of the write method is to rewrite the value of x to 1, and the function of the read method is to read the value of x.

If there are two threads that execute the write and read methods respectively, then since there is no coordination mechanism between the two threads, the code in the write and read methods does not have a happens-before relationship, and the visibility of the variables cannot be guaranteed , Let’s use an example to illustrate this situation.

For example, suppose that thread 1 has executed the write method first and modified the value of shared variable x, and then thread 2 executes the read method to read the value of x. At this time, we are not sure whether thread 2 can read the previous thread 1 For the modification made to x, thread 2 may see this modification, so the value of x read is 1, or it may not see this modification, so the value of x read is the initial 0. Since there is uncertainty, the code in the write and read methods does not have a happens-before relationship. Conversely, if the first operation happens-before the second operation, then the first operation must be visible to the second operation.

Let's take a look at what specific rules the happens-before relationship contains.

What are the rules of the Happens-before relationship?

If there are operations x and y respectively, use hb(x, y) to represent x happens-before y.

(1) Single-thread rule:
In a single thread, according to the order of the program code, the operations performed first happen-before and then the operations performed. In other words, if operation x and operation y are two operations in the same thread, and x appears before y in the code, then there is hb(x, y), as shown in the figure below

Insert picture description here
This happens-before rule is very important, because if the latter statement cannot guarantee that the execution result of the previous statement can be seen within the same thread, it will cause very serious consequences, and the logic of the program cannot be guaranteed. Up.

Here is a note. We talked about reordering before. Does that mean that the happens-before relationship rules and reordering conflict. In order to satisfy the happens-before relationship, reordering cannot be done?

the answer is negative. In fact, as long as the result of the reordering still conforms to the happens-before relationship, that is, visibility can be guaranteed, then the occurrence of reordering will not be restricted. For example, in a single thread, statement 1 is before statement 2, so according to the "single-thread rule", statement 1 happens-before statement 2, but it does not mean that statement 1 must be executed before statement 2, such as statement 1 modified Is the value of variable a, and the content of statement 2 has nothing to do with variable a, then statement 1 and statement 2 may still be reordered. Of course, if statement 1 modifies variable a, and statement 2 happens to read the value of variable a, then statement 1 must be executed before statement 2.

(2) Lock operation rules (synchronized and Lock interface, etc.):

If operation A is unlocking, and operation B is locking the same lock, then hb(A, B). As shown in the figure below:
Insert picture description here
As you can see from the figure above, there are two threads, thread A and thread B. All operations of thread A before unlocking are visible to all operations of thread B after locking the same lock. This is the rules of the happens-before relationship of lock operations.

(3) Volatile variable rules:
the write operation of a volatile variable happen-before the subsequent read operation of the variable.

This means that if a variable is modified by volatile, then after each modification, other threads must be able to read the latest value of the variable when reading this variable. We have introduced the volatile keyword before, knowing that it guarantees visibility, and this is exactly what this rule stipulates.

(4) Thread start rule:
The start method of the Thread object happen-before each operation in the thread run method. As shown in the figure below:
Insert picture description here
In the example in the figure, thread A starts a child thread B in the left area, and the right area is child thread B, so when child thread B executes the statement in the run method, it must You can see the results of all operations performed by the parent thread before threadB.start().

(5) Thread join rules:

We know that join can make threads wait. Suppose thread A starts a new thread B by calling threadB.start(), and then calls threadB.join(), then thread A will wait until thread B's run method ends (not Consider interruption and other special cases), and then the join method returns. After the join method returns, all subsequent operations in thread A can see the results of all operations performed in the run method of thread B, that is, the operations in the run method of thread B happen-before the statement after the join of thread A . As shown below:

Insert picture description here
(6) Interruption rules:
The call to the thread interrupt method happens-before to detect the interrupt event of the thread.

That is to say, if a thread is interrupted by other threads, then when detecting the interruption (such as calling Thread.interrupted or Thread.isInterrupted method), you must see the occurrence of this interruption, and the detection result will not be inaccurate.

(7) Rules for concurrent tools:

  • A thread-safe concurrent container (such as HashTable) can definitely see the result of the put operation that occurred before that when it gets a certain value. In other words, thread-safe concurrent container deposit operations happen-before read operations.

  • Semaphore (Semaphore) it will release the license, it will also get the license. The operation of releasing the license here happens-before the operation of obtaining the license, that is to say, if there is an operation of releasing the license before obtaining the license, it must be visible when obtaining the license.

  • Future: Future has a get method that can be used to get the result of the task. Then, when the get method of Future gets the result, you must be able to see the results of all operations in the previous task, that is to say, all operations in the Future task happen-before Future's get operation.

  • Thread pool: If you want to use the thread pool, you need to submit tasks (Runnable or Callable) to it. There is also a happens-before relationship rule, that is, the operation of submitting tasks happens-before task execution.

to sum up

Understand the happens-before relationship. Then give an example that does not have a happens-before relationship; next we focus on the many rules of the happens-before relationship. Most of these rules are familiar to you or do not need to be remembered, but here What you need to remember is the happens-before rule of lock operation and the happens-before rule of volatile, because they are closely related to the use of synchronized and volatile. You don’t need to focus on the happens-before rules of thread startup, thread join, thread interruption, and concurrency tools, because under normal circumstances, these rules will be used as known conditions by default.

Guess you like

Origin blog.csdn.net/Rinvay_Cui/article/details/111058941