The interviewer, you do not ask --JAVA the memory model (simplified)

In the interview, the interviewers are like many asked, JMM clearly? Talk about what is the visibility of memory, what is the reordering? synchronized, volatile and final in principle? And so these types of issues. And a search online, Infoprogramme a lot of things more chaotic, it is difficult to disguise the interviewer questions answered clearly. Finally, I determined to give everyone a stroke stroke JAVA simplified version of the memory model.

1 Introduction.

Java concurrency uses a shared memory model, communication is always implicit between Java threads, the entire communication process is completely transparent to the programmer.

2, JMM briefly.

JMM is a Java memory model, which determines a thread writes to shared variables when visible to another thread. From an abstract point of view, JMM defines an abstract relationship between the thread and the main memory: shared memory variables between threads in main memory (Main Memory), each thread has an abstract (real non-existent) local memory (local memory), a local memory to store the thread to read, write copy of the shared variable.

:( knowledge points above JMM supplement called "shared variable" mainly in the java heap)

JVM内存模型包括:
(1) 程序计数器。一块很小的内存空间,用于记录下一条要运行的指令。是线程私有的内存。
(2)java虚拟机栈。它和java线程同一时间创建,保存了局部变量、部分结果,并参与方法的调用和返回。是线程私有的内存。
(3)本地方法栈。它和java虚拟机栈的功能相似,主要为Native方法服务。是线程私有的内存。
(4)java堆。为所有创建的对象和数组分配内存空间。是线程共有的内存。
(5)方法区。也被称为永久区,与堆空间相似。是线程共有的内存。

复制代码

3, the reordering JMM.

When executing the program, in order to improve performance, often have compiler and processor instructions do reordering. However, before the final implementation of the program, but also to make reordering a memory.

Reordering may result in a multithreaded program memory visibility problems. See code examples:

  class ReorderEample {
        int a = 0;
        boolean flag = false;
        //写操作
        public void writer() {
            a = 1 ;  // (1)
            flag = true; //(2)
        }
        //读操作
        public void reader() {
            if (flag) {    //(3)
                int i = a * a;  //(4)
                // 处理逻辑
            }
        }
    }
复制代码

flag variable is a marker, identifying whether a has been written. Suppose there are two threads A and B, A write operation is first performed writer (), followed by B followed by a read operation Reader () method. Then thread B while performing an operation (4), to see whether the thread A write operation to the shared variable a (1) When? The answer is not able to see. Because in the reordering, A thread may first identify the flag variable, and then to write a variable, but occurs between them, B thread to read this time, the semantics of the program is broken. FIG execution timing following procedure:

4, volatile memory semantics

The JMM, is declared as volatile shared variables, thread exclusive lock get this variable, make sure that the thread is visible through. In order to achieve volatile memory semantics, the compiler generates bytecode when, will be inserted in the instruction sequence memory barrier to inhibit a particular type of processor reordering. Understanding Memory barrier for details see the Java Memory Model Cookbook (two) memory barrier

Characteristics 4.1, volatile of

  • Visibility. Reading of a volatile variable always see (any thread) last write this volatile variable.
  • Atomicity. Of any single variable volatile read / write atomic. But for a plurality of types of volatile or volatile ++ operations such composite operations are not atomic.

4.2, volatile reordering problem solving

volatile following the happens-before principle. Consider the following code:

class ReorderEample {
        int a = 0;
        volatile boolean flag = false;
        //写操作
        public void writer() {
            a = 1 ;  // (1)
            flag = true; //(2)
        }
        //读操作
        public void reader() {
            if (flag) {    //(3)
                int i = a * a;  //(4)
                // 处理逻辑
            }
        }
    }
复制代码

After thread A execution is assumed writer () method, the thread B executed Reader () method. According happens-before principle, this process of establishing a happens-before relationship is divided into three categories:

    1. The program sequence rules, (1) happens-before (2); (3) happens-before (4).
    1. The volatile rules, (2) happens-before (3).
    1. The transfer happens-before the rules, (1) happens-before (4).

It happens-before relationship is as follows:

For the previous example, this example only to increase the volatile flag variable declaration. After the thread writes to a volatile variable A, B thread reading the same volatile variable. A thread all visible shared variables, thread B after reading the same volatile variable is immediately visible to thread B before writing volatile variables.

happens-before rule knowledge points to add:

(1)程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作
(2)监视器锁规则:对一个线程的解锁,happens-before于随后对这个线程的加锁
(3)volatile变量规则:对一个volatile域的写,happens-before于后续对这个volatile域的读
(4)传递性:如果A happens-before B ,且 B happens-before C, 那么 A happens-before C
(5)start()规则:如果线程A执行操作ThreadB_start()(启动线程B) ,  那么A线程的ThreadB_start()happens-before 于B中的任意操作
(6)join()原则:如果A执行ThreadB.join()并且成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。
(7)interrupt()原则: 对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测是否有中断发生
(8)finalize()原则:一个对象的初始化完成先行发生于它的finalize()方法的开始。
复制代码

5, synchronized semantic memory

synchronized semantic memory and volatile memory semantics similar, concurrent programming in Java mechanisms, in addition to the critical section mutex lock, you can also make a thread releases the lock to acquire the same lock thread to send a message. Its core is the use of the underlying state variables declared in a volatile state to maintain synchronization.

5.1, synchronized to solve the problem of reordering

Lock also happens-before to follow the rules. Consider the following code:

  class MonitorExample{
        int a = 0;
        //写操作
        public synchronized void writer() { //(1)
            a ++;                           //(2)
        }                                   //(3)
        //读操作
        public synchronized void reader() { //(4)
            int i = a;                      //(5)
            //处理逻辑
        }                                   //(6)
    }
复制代码

Suppose thread A executed writer () method, then thread B executed Reader () method. The happens-before rule, happens-before relation of this process can be divided into three categories comprising:

    1. The program sequence rules, (1) happens-before (2), (2) happens-before (3), (4) happens-before (5), (5) happens-before (6).
    1. The monitor lock rules, (3) happens-before (4).
    1. The transfer rules, (2) happens-before (5).

It happens-before relationship is as follows:

A thread after the release of the lock, then thread B to acquire the same lock. Since then (2) happens-before (5), so that all visible thread A shared variables acquire a lock on the same thread B to B before releasing the lock thread becomes visible.

6, final semantic memory

In the JMM, the memory barrier prohibiting the compiler to write reorder final field to the outside of the constructor. Therefore, the object reference before any thread visible, final domain object has been properly initialized (null is not the case of) a. For the final field, and a processor compiler reordering follows two rules:

  • Written in the constructor of a final field, and then the object referenced this configuration assigned to a reference variable, not reordering between these two operations.
  • Reading a first object comprising a final medical domain, and then read the final initial field, the reordering is not between these two operations.

The following two examples will be described by two rules.

6.1, an example of a

public class FinalExample {
    int i;                           //普通变量
    final int j;                     //final变量
    static FinalExample obj;
    public FinalExample(int j) {     //构造函数
        i = 1;                       //写普通域
        this.j = j;                  //写final域
    }
    
    public static void writer() {    //写线程A执行
        obj = new FinalExample(2);
    }
    
    public static void reader() {    //读线程B执行
        FinalExample object = obj;   //读引用对象
        int a = object.i;            //读普通域
        int b = object.j;            //读final域
    }
}
复制代码

Normal operation of the write field to be compiled discouraged sorted constructor outside thread B reads the value of the plain erroneously read before initialization of the variable i. After the write operation and the final field is re-written final collation domain "is defined" within the constructor, the thread B reads correctly read the final value of the variable initialization. Execution timing is as follows:

6.2 Example Two

public class FinalReferenceExample {
    final int[] intArray;
    static FinalReferenceExample obj;

    public FinalReferenceExample() {   //构造函数
        intArray = new int[1];         //(1)
        intArray[0] = 1;               //(2)
    }

    public static void writeOne() {         //写线程A执行
        obj = new FinalReferenceExample();  //(3)
    }

    public static void writeTwo() {         //写线程B执行
        obj.intArray[0] = 2;                //(4)
    }

    public static void reader () {         //读线程C执行
        if (obj != null) {                 //(5)
            int temp = obj.intArray[0];    //(6)
        }
    }
}
复制代码

A first thread execution writeOne () method is executed after the thread B executed writeTwo method, after the implementation of the thread C executed reader method. Operation (1) of the final field is written, the operation (2) is a member of the object field references final write operation (3) is configured to reference an object is assigned to a reference variable. Here in addition to (1) and (3) can not be reordered, (2) and (3) can not be reordered. Therefore, a thread of execution timing of the program is unknown, because there is competition between data read and write thread B thread C.

Reference: "Java concurrent programming art" Xiaoming Fang Tengfei Wei Pengcheng "in-depth understanding of the Java Virtual Machine," Zhou Zhiming

If this article useful for you, you point a praise it! Your support is my share of power.

Guess you like

Origin juejin.im/post/5d0e449be51d45772a49ad61