Wechat official account: Rhubarb Run follow me for more interesting interview questions.

Written in the book before

Hello, I’m Rhubarb, a programmer who can only write HelloWorld.

Concurrent programming in Java is the focus of each large factory interview, many knowledge points are difficult to understand, often need to combine with practical experience to answer some interview questions, the answer is not good, easy to be directly failed by the interviewer.

Therefore, Rhubarb spent the weekend, painstaking, sorting out the previous and the interviewer battle interview topics.

Since there are too many concurrent questions, one article is not enough to cover all concurrent knowledge points, so I plan to analyze them in several articles, and how to answer concurrent questions in the interview. This article focuses on the volatile keyword.

On concurrent programming some source code and deep analysis has been too numerous to enumerate, rhubarb is not going to launch from all aspects, only hope to be able to use this article to communicate how to answer the interview, after all, the interview time is short, answer key points, key points is the key.

An overview of interview questions

Below I list some big factory interview, about concurrent programming common some interview questions, some of their own experience, some looking for net friends to share the experience.

Take a look at these interview questions and think about how you would respond if you were faced with them.

  1. Volatile to explain bytedance
  2. What does volatile do, and how does it work?
  3. The difference between synchronized and volatile
  4. The principle of volatile
  5. Volatile: Memory model: Volatile
  6. Volatile Underlying principles, usage scenarios

As you can see, the keyword volatile has become a must-ask in interviews at large companies. A good answer is a plus, a bad answer is hey hey, you know.

The interview review

A gray plaid shirt, holding flashing huge 🍎logo small brother head on, I thought, logo also has its own light, this is certainly p7 big guy, but we still have to calm down at the beginning is not.

Interviewer: Rhubarb, I see that you have mastered the core knowledge of concurrent programming, so let’s take a look at some core knowledge of concurrent programming first. Have you heard of volatile? Tell me what you think of this.

Remember to ask why, what and what does it do to impress the interviewer.

Rhubarb: Hello, interviewer. Volatile is a lightweight synchronization mechanism provided by the Java virtual Machine. It has three main features:

  1. Ensure visibility between threads
  2. Disallow command reordering
  3. But atomicity is not guaranteed

In the interview, certainly not finish these three points, generally need to expand.

Rhubarb: Visibility is unique in multiple threads. After thread A changes the value, thread B can know that the parameter has changed, which is called inter-thread visibility. After USER A modifies the shared variable I, user B can sense the change immediately.

The interviewer may ask why variable visibility is a problem. This involves the Java memory model (commonly known as JMM), so you need to talk briefly about the Java memory model.

Interviewer: So why does variable visibility come up?

Each time a thread is created, the JVM creates its own working memory for the thread. Note that the working memory is unique to the thread. This means that other threads cannot access the information in the working memory. In the Java memory model, all variables are stored in the main memory, which is an area shared by multiple threads. The operation (reading and writing) of variables by threads must be carried out in the working memory.

Don’t talk about theory. Use examples to make the interviewer feel like you’ve got it. The above problem you grasp the main memory, thread memory can be elaborated separately.

Rhubarb: for example, there are two threads of A and B, at the same time to obtain an object from the main thread (I = 25), A moment, I in the A and B of worker threads are 25, A higher efficiency, for A moment, after A change, I will update to the main memory immediately, but at this point B is completely there is no way I changed, still use I do some operations. The problem is that thread B can’t sense the change right away!

Rhubarb visibility Demo Demo episode

import lombok.Data;

/ * * *@author dahuang
 * @time2020/3/15 immediately *@DescriptionJMM atomicity simulation */
public class Juc002VolatileAtomic {
    public static void main(String[] args) {
        AtomicResource resource = new AtomicResource();

        // Create 20 threads using the for loop, with each thread incrementing 100 times
        for(int i = 0; i < 20; i++){
            new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    resource.addNum();
                }
            },String.valueOf(i)).start();
        }

        // Use this method to determine whether the above 20 threads have been calculated.
        // If it is less than 2, the calculation thread is not finished, and the main thread temporarily gives up the execution time
        while (Thread.activeCount() > 2){
            Thread.yield();
        }
        // Check if number can guarantee atomicity, if so, output value 2000
        System.out.println("Result = "+resource.getNumber()); }}@Data
class AtomicResource{

    volatile int number = 0;

    public void addNum(a){ number++; }}Copy the code

Here is the result:

Result = 1906

Process finished with exit code 0

Interviewer: Does volatile guarantee atomicity? Rhubarb: The JMM is intended to address atomicity, but volatile does not guarantee atomicity. Why can’t you guarantee atomicity? Because of the above Java memory model, changing the value of an I is not a one-step operation. The process can be divided into three steps:

  1. Read the value from main memory and load it into working memory
  2. I increment in working memory
  3. Write back to main memory after the increment is complete.

Each thread retrieves a value change in main memory and then writes it back to main memory. When multiple threads execute, there are many cases of write overwrites.

Rhubarb visibility Demo Demo episode

Use the following example to test whether volatile guarantees atomicity.

import lombok.Data;

/ * * *@author dahuang
 * @time2020/3/15 immediately *@DescriptionJMM atomicity simulation */
public class Juc002VolatileAtomic {
    public static void main(String[] args) {
        AtomicResource resource = new AtomicResource();

        // Create 20 threads using the for loop, with each thread incrementing 100 times
        for(int i = 0; i < 20; i++){
            new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    resource.addNum();
                }
            },String.valueOf(i)).start();
        }

        // Use this method to determine whether the above 20 threads have been calculated, if less than 2,
        // If the thread is not finished calculating, the main thread temporarily gives up execution time
        while (Thread.activeCount() > 2){
            Thread.yield();
        }
        // Check if number can guarantee atomicity, if so, output value 2000
        System.out.println("Result = "+resource.getNumber()); }}@Data
class AtomicResource{

    volatile int number = 0;

    public void addNum(a){ number++; }}Copy the code

The results are as follows:

Result = 1906

You can see that the program loops 2000 times, but only adds up to 1906, indicating a lot of overwriting in the program.

The interviewer may think, boy, you know a lot. Let me test your skills.

Interviewer: What if you want to ensure atomicity in your program? Rhubarb: Juc(Java and package abbreviation) the following provides a variety of ways, relatively lightweight variables with Atomic class, more heavyweight Synchronized keyword modification, the former efficiency itself is the latter high, without locking can ensure atomicity.

Rhubarb visibility Demo Demo episode

import lombok.Data;

import java.util.concurrent.atomic.AtomicInteger;

/ * * *@author dahuang
 * @time 2020/3/15 17:43
 * @DescriptionUse Atomic to ensure atomicity */
public class Juc003VolatileAtomic {
    public static void main(String[] args) {
        AtomicResource resource = new AtomicResource();

        // Create 20 threads using the for loop, with each thread incrementing 100 times
        for(int i = 0; i < 20; i++){
            new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    resource.addNum();
                }
            },String.valueOf(i)).start();
        }

        // Use this method to determine whether the above 20 threads have been calculated, if less than 2,
        // If the thread is not finished calculating, the main thread temporarily gives up execution time
        while (Thread.activeCount() > 2){
            Thread.yield();
        }
        // Check if number can guarantee atomicity, if so, output value 2000
        System.out.println("Result = "+resource.getNumber()); }}@Data
class AtomicResource{

    AtomicInteger number = new AtomicInteger();

    public void addNum(a){ number.getAndIncrement(); }}Copy the code

The following output is displayed:

Result = 2000

Interviewer: You talked about the rearrangement of volatile prohibitions. Can you explain how that works? This is the moment to pretend to be reflective, to appear to be remembering (why, you know, no interviewer likes to memorize questions). Rhubarb: Oh, I’ve seen this before. When the computer executes the program at the bottom level, in order to improve efficiency, it often resorts the instructions. Generally, the reordering can be divided into three types

  1. Compiler optimized reordering
  2. Rearrangement of instruction parallelism
  3. Rearrangement of memory systems

Under single thread, no matter how to reorder, the final execution results are consistent, and instruction reordering follows the basic data dependence principle, data should be declared before calculation; In multithreading, threads are executed alternately. Due to the compiler’s optimization rearrangement, the consistency of the variables used in the two threads is uncertain and the results are unpredictable.

The principle of volatile itself is to use memory barriers to prevent reordering optimizations of instructions before and after the barriers by inserting them. Interviewer: So what does a memory barrier do and how does it work?

Rhubarb:

  1. Ensure the order in which certain operations are performed
  2. Ensure memory visibility of certain variables.

Interviewer: How do Volatile and memory barriers work?

Writes to Volatile variables are followed by a store barrier instruction that flushs shared values from working memory to main memory. Read operations on Volatile variables are preceded by a load barrier that reads data from main memory immediately before reading.

The interviewer thought, Yes, this young man has some depth. I’ll see if he’s used it. Where do you use volatile in your work?

Rhubarb: Singletons If you must ensure singletons across multiple threads, the volatile keyword is essential.

Interviewer: Can you briefly write down the common singleton pattern?

Let’s first look at the common singleton pattern:

public class Juc004SingletonMultiThread {
    /** * privatize the constructor, construct only once */
    private Juc004SingletonMultiThread(a){
        System.out.println("Construction method");
    }

    private static Juc004SingletonMultiThread instance = null;

    public  static Juc004SingletonMultiThread getInstance(a){
        if(instance == null) {synchronized (Juc004SingletonMultiThread.class){
                if(instance == null){
                    instance = newJuc004SingletonMultiThread(); }}}return instance;
    }

    public static void main(String[] args) {

        // new 30 threads and watch how many times the constructor is created
        for (int i = 0; i < 30; i++) {
            newThread(()->{ Juc004SingletonMultiThread.getInstance(); },String.valueOf(i)).start(); }}}Copy the code

Rhubarb: Note that this is extremely strong singleton mode. However, the near-thread-safe singleton pattern of double-checking can also be problematic because there is an underlying instruction reordering, the order of checks can change, and instance! =null, but instance’s reference object may not be initialized. , causing another thread to read the uninitialized result.

Interviewer: Why did this happen?

Rhubarb: This may need to start with the object initialization process. So, Pangu made the world… Sorry, off topic. Let’s move on.

   // step 1
public  static Juc004SingletonMultiThread getInstance(a){                 
   // step 2
  if(instance == null) {// step 3
    synchronized (Juc004SingletonMultiThread.class){             
    // step 4
      if(instance == null) {// step 5
        instance = newJuc004SingletonMultiThread(); }}}return instance;
}
Copy the code

Step 5 The initialization process is divided into three steps:

  1. Allocates object memory spacememory = allocate()
  2. Initialize an objectinstance(memory)
  3. Set instance to the newly allocated memory addressinstance = memory

Using this initialization again, the object looks nice together, but the underlying computer compiler, hoping to speed you up, might smartly reorder the third and second steps to optimize them

  1. Memory = allocate() Allocates object memory space
  1. Instance = memory Sets instance to the newly allocated memory address, while the object does not have one
  2. Instance (memory) initializes the object

This optimization does not matter under a single thread, since the first access to the object must be after all three steps, but there is so much contention between multiple threads that it would be a problem if another thread accessed the object after 3 after the reorder, because the object was completely initialized at all.

Interviewer: Boy, this guy, he has to. Can I simply draw to access the picture?

Rhubarb picked up a pen and drew the following picture:But this problem does not exist with single threads, it only occurs with multiple threads. There are two ways to solve this problem,

  1. Reordering of 2 and 3 is not allowed
  2. 2 and 3 reorders are allowed, but other threads are not allowed to see the reorder.

Therefore, the Volatile keyword can be added to prevent instruction reordering.

Interviewer: Write about the singleton pattern implemented with volatile

public class Juc004SingletonMultiThread {
    /** * privatize the constructor, construct only once */
    private Juc004SingletonMultiThread(a){
        System.out.println("Construction method");
    }

    private  static volatile Juc004SingletonMultiThread instance = null;

    public  static Juc004SingletonMultiThread getInstance(a){
        if(instance == null) {synchronized (Juc004SingletonMultiThread.class){
                if(instance == null){
                    instance = newJuc004SingletonMultiThread(); }}}return instance;
    }

    public static void main(String[] args) {

        // new 30 threads and watch how many times the constructor is created
        for (int i = 0; i < 30; i++) {
            newThread(()->{ Juc004SingletonMultiThread.getInstance(); },String.valueOf(i)).start(); }}}Copy the code

At this point in the interview, I think the interviewer has no doubt about your ability. Interviewer secretly pleased, hey hey, met treasure, good boy, have something, this kind of talent must have to win.

Interviewer: Ok, that’s all for today’s interview. May I ask when you are available for the next interview? I’ll arrange it.

Ha ha ha, congratulations to you, here has been successful in the interview, put away your smile.

Rhubarb: I’m free these days. It depends on your arrangement.

conclusion

It centers on the first few real interview questions. In a nutshell, what is volatile? Why volatile? The underlying principle of Volatile? Where volatile is used in normal programming.

Finally, Rhubarb shares his years of interview experience. During the interview, when faced with a question, answer it according to the logic of the total score. Present the conclusion directly, and then demonstrate your conclusion with examples. Be sure to grasp the interviewer’s mind for the first time, otherwise it is easy to give people the impression of missing the point or irrelevant.

One day

In addition, pay attention to the rhubarb running public number, the first time to harvest the exclusive arrangement of the interview actual combat record and interview knowledge summary.

I’m Rhubarb, a programmer who can only write HelloWorld, and I’ll see you next time.