Java uses Happen-before rules to implement synchronous operation of shared variables

Source: Internet
Author: User

Objective

Familiar with Java concurrency programming knows that the Happen-before (HB) rule in JMM (Java memory model), which defines the order and visibility of Java multithreading operations, prevents the effect of compiler reordering on program results.

According to the official statement:

When a variable is read by multiple threads and written by at least one thread, there is a data contention problem if the read and write operations do not have HB relationships.

To ensure that 操作 B the thread sees 操作 A the results (whether A and B not on a thread), then the A B HB principle must be met between and, if not, it will likely result in reordering.

When the HB relationship is missing, a reordering problem can occur.

What are the rules for HB?

This people are very familiar with the should, most of the books and articles will be introduced, here a little review:

    1. Program Order rules: Within a thread, in the Order of code, written in front of the operation first occurs in the operation after writing;
    2. Locking rule: The unlock operation on the monitor lock must be performed before the lock operation on the same monitor.
    3. Volatile variable rule: The write operation of a variable precedes the read operation of the variable;
    4. Delivery rule: If operation a precedes operation B, and Operation B precedes Operation C, it can be concluded that operation a precedes operation C;
    5. Thread Initiation rule: the Start () method of the thread object takes precedence over each action of this thread;
    6. Thread break rule: the invocation of the thread interrupt () method occurs when the code of the interrupted thread detects that the interrupt event occurred;
    7. Thread termination rule: All operations in a thread occur first in the thread termination detection, and we can detect that the thread has terminated execution by means of the Thread.Join () method end, Thread.isalive () return value.
    8. Object Finalization rule: Initialization of an object occurs at the beginning of his finalize () method;

Among them, the delivery rules I bold, this rule is very important. how to skillfully use delivery rules is the key to achieving synchronization .

Then, a different angle to explain HB: When an operation a HB operation B, then operation A on the shared variable operation result is visible to Operation B.

At the same time, if Operation b HB Operation C, then operation A on the shared variable operation result is visible to the Operation B.

The realization of the principle of visibility is the cache protocol and memory barrier. Visibility is achieved through cache conformance protocols and memory barriers.

How do I synchronize?

In Doug Lea's book, "Java Concurrency in practice", there are the following descriptions:

The book mentions that by combining some of the rules of HB, you can achieve the visibility of an unlocked protected variable.

But because this technique is sensitive to the order of the statements, it is prone to error .

Landlord Next, you will demonstrate how to synchronize a variable with volatile rules and procedural order rules.

Here's a familiar example:

classThreadprintdemo {Static intnum =0;Static volatile BooleanFlag =false; Public Static void Main(string[] args) {Thread T1 =NewThread ((), { for(; -> num; ) {if(!flag && (num = =0|| ++num%2==0)) {System. out.println(num); Flag =true;    }      }    }    ); Thread t2 =NewThread ((), { for(; -> num; ) {if(Flag && (++num%2!=0)) {System. out.println(num); Flag =false;    }      }    }    ); T1.Start(); T2.Start(); }}

The purpose of this code is to print 0-100 digits at two thread intervals.

The classmate who is familiar with concurrent programming must say that this num variable does not use volatile, there will be a visibility issue, namely: T1 thread update num,t2 thread is not aware of.

Haha, the landlord just started to think so, but recently by studying the HB rules, I found that removing NUM's volatile modification is also possible.

We analyze, the landlord drew a picture:

We analyze This diagram:

    1. First, red and yellow indicate different threading operations.
    2. The red thread makes the NUM variable + +, and then modifies the volatile variable, which is compliant 程序次序规则的 . That means 1 HB 2.
    3. The red thread writes the HB yellow thread to the volatile read, which is 2 HB 3.
    4. The yellow thread reads the volatile variable, then the NUM variable is done with + +, 程序次序规则 which is 3 HB 4.
    5. According 传递性规则 to, 1 certainly HB 4. So,1 of the changes are visible to 4.

Note: The HB rule guarantees that the result of the previous operation is visible to the next operation.

So, in the applet above, thread A modifies num, and thread B is fully aware-even if NUM does not use the volatile modifier.

In this way, we use the HB principle to achieve a synchronous operation of a variable, that is, in the multi-threaded environment, to ensure the concurrent modification of shared variables security. And there is no use of Java primitives for this variable: volatile and synchronized and CAS (assuming it is counted).

This may seem unsafe (actually safe), and it doesn't seem easy to understand. Because all of this is achieved by the HB bottom cache protocol and memory barrier.

Other rules for synchronization
    1. Use thread termination rules to implement:
  staticint1;  publicstaticvoidmain(String[] args) {    new Thread(() -> {      2;    });    new Thread(() -> {      try {        tb.join();      catch (InterruptedException e) {        //NO      }      System.out.println(a);    });    ta.start();    tb.start();  }
    1. Using the thread start rule implementation:
  staticint1;  publicstaticvoidmain(String[] args) {    new Thread(() -> {      System.out.println(a);    });    new Thread(() -> {      tb.start();      2;    });    ta.start();  }

These two operations can also guarantee the visibility of variable A.

It's really a bit of a reversal of the idea. In the previous concept, if a variable was not modified by a volatile or final modification, it would be unsafe to read and write under multiple threads-because there would be a cache, which would result in the reading being not up-to-date.

However, through the use of HB, we can achieve.

Summarize

Although the title of this article is to realize the synchronous operation of shared variables through Happen-before, but the main purpose is to understand happen-before more deeply, understanding his Happen-before concept is to ensure that the multi-threaded environment, The order of the last operation and the visibility of the result of the operation.

At the same time, two threads can be synchronized by flexible use of transitive rules and the combination of rules--implementing a specified shared variable without using the primitives can also guarantee visibility . Although this may not seem easy to read, it is also an attempt.

Doug Lea gives practice in JUC on how to combine rules to achieve synchronization.

For example, the old version of the Futuretask internal class Sync (has disappeared), through the Tryreleaseshared method to modify the volatile variable, tryacquireshared read the volatile variable, which is the use of volatile rules;

By setting a non-volatile result variable before tryreleaseshared, and then reading the result variable after tryacquireshared, this takes advantage of the program order rule.

This guarantees the visibility of the result variable. Similar to our first example: the use of program order rules and volatile rules to achieve common variable visibility.

Doug Lea himself said that the "help" technique is very error-prone and should be used with caution. But in some cases, this "with" is very reasonable.

In fact, Blockingqueue is also the rule of "using" the Happen-before. Do you remember the unlock rules? When the unlock occurs, the inner element must be visible.

And there are other operations in the class library "with" the Happen-before Principle: concurrent containers, Countdownlatch,semaphore,future,executor,cyclicbarrier,exchanger and so on.

In a word, in short:

The Happen-before principle is the core of the JMM, and the compiler will reorder the code only if the HB principle is met to ensure order and visibility. HB even defines the rules for lock and volatile.

Proper use of common shared variables can be achieved through appropriate combinations of HB rules.

Java uses Happen-before rules to implement synchronous operation of shared variables

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.