Ali three sides: Can Java's synchronized prevent instruction reordering?



Ergou : Erfat, did you ask for leave yesterday, did you go to the interview again?
Er Pang : Don't say anything, I'll go out and test the water, see if I can find a job now, and go out to find a blow, and then I can calm down and study hard.
Ergou: How about being hit? You know what level you are, smirk.
Erpang: The basics are too poor, so I have to go back and wait for the notification. I have to study hard, so I won't talk nonsense with you.
Ergou: What questions did they ask you, and they beat you like this? Let me get ready for the review together.
Erpang : Well, since you're so curious, I'll talk about it. It's good for you to move on to the small bench and be careful. I'm about to start my show.
The following two fat first side began.
Interviewer : Er fat, right? Let me introduce myself first.
Erpang : Yes, my name is Erpang, I am from Changsha, I am 25 years old and I have been engaged in java development for almost 3 years. Now I am a senior java development engineer in the XX division of XX company, mainly responsible for the XX system. . . . .
Interviewer : OK, I see your resume says you are proficient in concurrent programming. Can you tell me which keywords you know about concurrent programming?
Two fat: Is not that what you want to test me synchronized and volatile that I'm good at, ah, I deliberately memorized, synchronized is java A keyword provided can mainly guarantee atomicity and ordering. Its bottom layer is mainly realized by Monitor . volatile is also a keyword in java. Its main function is to ensure visibility. . . . 1000 words are omitted here.
Interviewer : The eight-part essay is pretty good. Having said so much, let's try it out. I'll take a look at the singleton of writing a double-check lock ( dcl ).
Erpang: I took out the pen from my butt pocket and wrote it out by dictation.
Interviewer : You have said volatile keyword and synchronized keyword. synchronized can guarantee atomicity, ordering and visibility. And volatile can only guarantee order and visibility. Then, let's take a look at the singleton implemented by the double check lock. We have already used synchronized , why do we need volatile ? Can this volatile be removed?
Er Fat: Let me think about it, it seems that it can be removed.
Interviewer: Let's stop here for today's interview. We will contact you if there is news in the future. Thank you for coming to the interview today.

Erpang was very depressed and went back to google this question. There is also this question on stackoverflow . It seems that I am not the only one who doesn't know this question? It seems that the interview is not wrong
The above stories are purely fictitious, if there is any similarity, please use this article as the main one.

The ordering of synchronized?

Let's first look at the singleton without volatile decoration:

 1   public class Singleton {  
 2      private static Singleton singleton;  
 3       private Singleton (){}  
 4       public static Singleton getSingleton() {  
 5       if (singleton == null) {  
 6           synchronized (Singleton.class) {  
 7               if (singleton == null) {  
 8                   singleton = new Singleton();  
 9               }  
 10           }  
 11       }  
 12       return singleton;  
 13       }  
 14   }

Does the above code look okay?
First, let's take a look at what this line of code does

 singleton = new Singleton()

We can simplify the above process into 3 steps:

  • JVM allocates a piece of memory M for the object.
  • ②Initialize the object on the memory M.
  • ③ Copy the address of memory M to the singleton variable.
    There are two execution sequences for this step, which can be executed according to ①②③ or ①③② . When we execute in the order of ①③② , we assume that there are two threads ThreadA and ThreadB to request at the same time Singleton.getSingleton method:
  • Under normal circumstances, execute in the order of ①②③
    The first step: ThreadA to the 8th line, execute singleton = new Singleton() to initialize the object (according to the object initialization process ①②③ ) to complete the execution.
    The second step: ThreadB Enter the first 5 line judgment singleton is not empty (the first step has been initialized), directly return singleton
    Step 3: Get this object to do other operations.
    It looks like there is no problem.
  • Then if the object is initialized according to the steps of ①③② , let's take a look again:
    The first step: ThreadA into the line 8, to perform singleton = new Singleton() execution completed. ① JVM allocate a chunk of memory for the object M . ③Copy the address of the memory to the singleton variable.
    Step 2: At this point ThreadB go directly to line 5, find that singleton is not empty, then jump directly to singleton 12 line to get this- singleton Go back and perform the operation. At this time ThreadB got the singleton object is a semi-finished object, because it has not been initialized for this object ( ② has not been executed ).
    Step 3: So ThreadB the object obtained to execute the method may have exceptions. As for why this is listed? It is mentioned in "Java Concurrent Programming Practice"

    What happens with synchronized non-volatile DCL (double-checked locks): the thread may see the current value of the reference, but the state value of the object is rarely invalid, which means that the thread can see the object in an invalid or wrong state.

To put it bluntly, ThreadB can get an object that already has a reference but has not yet allocated memory resources.
If you want to solve the problem of creating objects in the order of ①②③, in fact, in order to solve the instruction rearrangement, you only need to add a volatile modification to the second line.
Isn't it said that synchronized can guarantee orderliness? The orderliness of volatile? Isn't synchronized enough to guarantee instruction reordering?
How to define the order? "In-depth understanding of the Java virtual machine third edition" mentioned

The natural ordering in Java programs can be summed up in one sentence: if observed within this thread, all operations are naturally ordered. If one thread observes another thread, all operations are out of order. The first half of the sentence refers to the "semantics that appear to be serial within the thread", and the second half of the sentence refers to the phenomenon of "instruction rearrangement" and "synchronization delay between working memory and main memory".
  • The ordering of synchronized means that two synchronized blocks holding the same lock can only enter serially, that is, the locked content must be executed by multiple threads in sequence, but the internal synchronization code will still be reordered, so that Orderly visible between blocks.
  • The ordering of volatile is to ensure that instructions are executed in order by inserting memory barriers. There will be no subsequent instructions to run before the previous instructions to be executed. It is to ensure that the instructions will not be out of order when the compiler optimizes.
  • synchronized does not guarantee instruction reordering .

**This article participated in the SegmentFault Sifu essay "How to "anti-kill" the interviewer?", you are welcome to join.


  • Due to my lack of knowledge and knowledge, it is inevitable that there will be mistakes. If you find any mistakes, please leave a message and point them out to me, and I will correct them.
  • If you think the article is not bad, your forwarding, sharing, appreciation, likes, and comments are the greatest encouragement to me.
  • Thank you for reading, you are very welcome and appreciate your attention.

Picking apples while standing on the shoulders of giants:

阅读 522
81 声望
14 粉丝
0 条评论
81 声望
14 粉丝