In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
Editor to share with you how Java uses happens-before rules to achieve the synchronization of shared variables, I believe most people do not know much about it, so share this article for your reference. I hope you will gain a lot after reading this article. Let's learn about it together.
Preface
Anyone familiar with Java concurrent programming knows the happens-before (hb) rule in JMM (Java memory Model), which defines the order and visibility of Java multithreaded operations and prevents the compiler reordering from affecting program results. According to official statement:
When a variable is read by multiple threads and written by at least one thread, data contention occurs if there is no HB relationship between the read operation and the write operation. To ensure that the thread of operation B sees the results of operation A (whether An and B are in the same thread or not), the HB principle must be met between An and B, and if not, it may lead to reordering. Reordering problems can occur when HB relationships are missing.
What are the rules of HB?
We are all very familiar with this. Most books and articles will be introduced. Here is a brief review:
Program order rule: within a thread, according to the code order, the operation written in front occurs first in the operation written later.
Locking rule: an unlock on a monitor lock must be performed before a lock on the same monitor.
Volatile variable rule: the write operation to a variable occurs first in the subsequent read operation on the variable
Transfer rule: if operation An occurs first in operation B, and operation B occurs in operation C first, it can be concluded that operation An occurs in operation C first.
Thread startup rule: the start () method of the Thread object occurs first in every action of this thread
Thread interrupt rule: the call to the thread interrupt () method occurs first in the code of the interrupted thread to detect the occurrence of the interrupt event
Thread termination rule: all operations in a thread first occur in the termination detection of the thread. We can detect that the thread has terminated execution through the termination of the Thread.join () method and the return value of Thread.isAlive ().
Object termination rule: the initialization of an object occurs first at the beginning of its finalize () method
Among them, I have thickened the rules of transmission, which is very important. How to skillfully use the delivery rules is the key to achieve synchronization.
Then, explain HB from another perspective: when an operation A HB operates B, then the results of the operation An on the shared variable are visible to the operation B.
At the same time, if operation B HB operation C, then the result of operation A's operation on the shared variable is visible to operation B.
The principles for achieving visibility are cache protocol and memory barrier. Visibility is achieved through cache consistency protocols and memory barriers.
How to achieve synchronization?
In Doug Lea's book Java Concurrency in Practice, there are the following descriptions:
It is mentioned in the book that by combining some of the rules of hb, you can achieve visibility into an unlocked protected variable.
However, because this technique is sensitive to the order of statements, it is prone to errors.
Next, we will demonstrate how to synchronize a variable through volatile rules and program order rules.
Let's take a familiar example:
Class ThreadPrintDemo {static int num = 0; static volatile boolean flag = false; public static void main (String [] args) {Thread T1 = new Thread (()-> {for (; 100 > num;) {if (! flag & & (num = = 0 | | + + num% 2 = = 0)) {System.out.println (num); flag = true;}}) Thread T2 = new Thread (()-> {for (; 100 > num;) {if (flag & & (+ + num% 2! = 0)) {System.out.println (num); flag = false;}}); t1.start (); t2.start ();}}
The purpose of this code is to print a number of 0-100 at intervals between the two threads.
Students familiar with concurrent programming will definitely say that this num variable does not use volatile, there will be a visibility problem, that is, the T1 thread updates the num,t2 thread unaware.
Haha, the landlord thought so at first, but recently, through the study of HB rules, I found that it is possible to remove the volatile modification of num.
Let's analyze it. The landlord drew a picture:
Let's analyze this picture:
First, red and yellow represent different thread operations.
The red thread does + + to the num variable, and then modifies the volatile variable, which is in accordance with the program order rules. That's 1 HB 2.
Red thread writes to volatile HB yellow thread reads volatile, that is, 2 HB 3.
The yellow thread reads the volatile variable, and then does + + to the num variable, which conforms to the program order rule, that is, 3 HB 4.
According to the transitivity rule, 1 affirms HB 4. Therefore, the modification of 1 is visible to 4.
Note: the HB rule ensures that the results of the previous action are visible to the next action.
So, in Mini Program above, thread A's modification to num, thread B is fully aware-- even if num is not decorated with volatile.
In this way, we realize the synchronous operation of a variable with the help of HB principle, that is, in a multithreaded environment, we ensure the security of concurrent modification of shared variables. And there is no Java primitive for this variable: volatile and synchronized and CAS (assuming calculation).
This may seem insecure (in fact) and it may not seem easy to understand. Because all this is implemented by cache protocol and memory barrier at the bottom of HB.
Other rules are synchronized
Using thread termination rules to implement:
Static int a = 1; public static void main (String [] args) {Thread tb = new Thread (()-> {a = 2;}); Thread ta = new Thread (()-> {try {tb.join ();} catch (InterruptedException e) {/ / NO} System.out.println (a);}; ta.start (); tb.start ();}
two。 Using thread start rules to implement:
Static int a = 1; public static void main (String [] args) {Thread tb = new Thread (()-> {System.out.println (a);}); Thread ta = new Thread (()-> {tb.start (); a = 2;}); ta.start ();}
These two operations can also ensure the visibility of variable a.
It does subvert the previous concept a little bit. In the past, if a variable was not modified by volatile or final, it must not be safe to read and write in multithreading-because there is a cache, what is read is not up-to-date.
However, with the help of HB, we can achieve this.
Summary
Although the title of this article is to synchronize shared variables through happens-before, the main purpose is to have a deeper understanding of happen-before. To understand his concept of happens-before is to ensure the order of the previous operation to the next operation and the visibility of the operation result in a multithreaded environment.
At the same time, through the flexible use of transitivity rules, and then combining the rules, the two threads can be synchronized-- the visibility of specified shared variables can be guaranteed without using primitives. Although this does not seem to be 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 inner class Sync (disappeared) of the old version of FutureTask modifies the volatile variable through the tryReleaseShared method, and tryAcquireShared reads the volatile variable, which makes use of the volatile rule
By setting the non-volatile result variable before tryReleaseShared and then reading the result variable after tryAcquireShared, this takes advantage of the program order rules.
This ensures the visibility of the result variable. Similar to our first example: using program order rules and volatile rules to achieve common variable visibility.
Doug Lea himself has said that this "with the help of" technology is very error-prone and should be used with caution. But in some cases, this kind of "help" is very reasonable.
In fact, BlockingQueue also "draws on" the rules of happens-before. Remember the unlock rules? When unlock occurs, the internal elements must be visible.
There are other operations in the class library that use happens-before principles: concurrency containers, CountDownLatch,Semaphore,Future,Executor,CyclicBarrier,Exchanger, and so on.
In a word, but in a word:
The happens-before principle is the core of JMM. Only if the hb principle is satisfied can the order and visibility be guaranteed, otherwise the compiler will reorder the code. Hb even defines rules for lock and volatile.
Through the proper combination of hb rules, the correct use of common shared variables can be realized.
These are all the contents of the article "how Java uses happens-before rules to synchronize shared variables". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.