In-depth understanding of JVM (two) JVM memory model

Original link: http://www.cnblogs.com/xuyuanpeng/p/11098601.html

I. Introduction

Above talked about memory into a virtual machine, that is, we share the memory into thread and thread private.
Java heap that is shared by the threads, and a method area. java heap we might have not unfamiliar; and the method area contains a constant pool, he is also known as permanent generations. The method is usually called the area will also be a non-heap, but logically, he is part of the java heap, and some virtual methods merger opportunities directly with the java heap.
Thread private virtual machine is stack, while the virtual machine stack, native method stacks, and program counter. Here we will not discuss the.
I will briefly review the above memory partition of the virtual machine, start the following text.

Two, java memory model DESCRIPTION

1, the main memory

java memory model specifies that all variables must be stored in the main memory of them.

2, working memory

Thread private memory every day, that working memory.
Working memory to save a copy of a copy of main memory variables of the thread used. What you did threads variables must be in working memory.
A different thread can not access each other's working memory variables, only through the main memory to achieve thread, information exchange between working memory, main memory, three.
Diagram is as follows:
Here Insert Picture Description
main memory, working memory, and in my last blog about the java heap memory area, stack area and other methods, is not the same level of memory division.
Different, easy to remember, we can understand:
the main memory is an example of a data portion corresponding to java heap, working memory corresponding to the partial region is the java virtual machine stack.
From the principle of the computer organization, so we can be understood, the main memory corresponds to the physical hardware memory, so if the main memory and process data exchange, it will be very time-consuming.
Working memory priority stored in registers and caches, because the program is running general access working memory.
(Part I at the beginning of the blog told about, put aside the operating system and virtual machine in terms of organizational principle, that is, bullying = _ =)

Third, on atomic Recollections

1, starting from a piece of code

No BB, show code

    private static volatile  int i = 0;
    public static  void add(){
        i++;
    }

    public static void main(String [] args){

        for(int c=0; c<20; c++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int k = 0; k<10000; k++){
                        add();
                    }
                }
            });
            thread.start();
        }
        while (Thread.activeCount()>1){
            Thread.yield();
        }
        System.out.println(i);
    }

If you read the above code, it can continue to read, if you have not seen the code above, under proposed here thinking, the final output value is how much?
Obviously, the result is not 200,000. (If the final result is 200,000, then why do I give this example =. =)

2, inside the virtual machine operating atoms

Whether their elders, or other people's suggestions have already mentioned, the problem with reading efficiency will be read than aimlessly, much better results, so I raised the issue of the above, the following is a natural amount of discussion in order to solve problems and expand instructions. Here, start with java virtual machine memory operation's start.

lock: the role of the main memory, the main memory of a variable flag is a thread exclusive.
unlock: acting on the main memory, the main memory variables, freed from the locked state, variable liberated, other threads can be re-occupied.
read: acting on the main memory, the main memory variables, transmitted from the main memory into the working memory.
load: on the role of working memory, will be read to the value, put a copy of the working memory of them.
use: the role of the working memory, the working memory of a variable passed to the execution engine. When the bytecode instructions executed by the virtual machine, when using this value, perform this operation.
assign: the role of the working memory, the value from the execution engine received, assigned to the working memory variables. Whenever the execution of an assignment statement bytecode will use this action.
store: a variable acting on the working memory, the variables in the working memory, transmission to the main memory.
write: acting on the main memory, the store acquired from working memory to the variables, which variables into the main memory.

3, the operation of dividing atoms

Atomic operations divided into two parts, in general, by the read, load, use, write read and write operations, etc., can guarantee the atomicity of data.
But sometimes we need the entire business code, have the atomicity, you need to use lock and unlock.

4, volatile description

Observant students may have found my code above. It is declared volatile during traversal.
So what is the role of volatile it?
In general, volatile variables of all threads are visible understanding. For volatile variable all writes, can understand the reaction to the other thread.
In other words, volatile are consistent across all threads, so all operations based at concurrent volatile variables are safe.
In actual fact, volatile variables, and can not guarantee the security concurrency.

(1) Results of comparison
Variable Types The results of 1 Execution result 2 The results of 3 The results of 4 The results of 5 Average value (extremal removed)
volatile 186632 196403 193658 197305 186825 192295
General variables 178387 179369 189835 174015 199458 182530

I recorded the results of five code. As shown in the table. Not our target 200,000. It is not that volatile variables declared and not declared, it is exactly the same?
After Definitely, I removed the volatile statement, execution results obtained, as the table shows.
Finally we concluded that the addition of volatile statement, the result is more closer to the target value. What causes this phenomenon is it?

(2) starts from the bytecode instructions

View bytecode There are generally two ways.
First, find a production class file, execute javap instructions, see the compiled code.
Second, if you use the idea editor (idea best in the world), you can select the java class you want to view, click the view menu click Show Bytecode.
Both ways, the way I usually choose two, two convenient way, and to view the code format in line with my reading habits.

 public static void add();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #2                  // Field i:I
         3: iconst_1
         4: iadd
         5: putstatic     #2                  // Field i:I
         8: return
      LineNumberTable:
        line 12: 0
        line 13: 8
Bytecode instructions volatile declaration object execution process description

Object volatile variable declarations, indeed, when he values in main memory changes, it would react to working memory immediately.
Here there is a node, that is, we bytecode

getstatic

getstatic directive, which is to obtain the most current real-time variable values. Subsequent to this value +1, and then returns. But there may be a case that when a +1 or return operation, other threads on this value were processed, resulting in the return value of this thread is not the correct value.
It may still not understand, we simulate what the scene.

  • Scene ①
    time 1: Thread A 1 obtain this value. (Fastest)
    time of 2: thread B acquires the value 1. (Times fast)
    time of 3: Thread obtain this value C 1 (slowest)
  • ② scene
    time point 4: A thread is finished processing the values, the values and write to main memory, the memory is finished emperor 2.
    moment 5: B thread, thread A in the main memory to modify the value of finished only begins getstatic command, he executed last is 2 + 1, is finished rear main memory 3
    time 6: C thread, getstatic method when executed, the thread a has finished writing data to the main memory, and thread B still performed +1 . In this case it is main memory 2. He again 2 +1 operation, after the implementation of the main memory 3 is written.
    So in the end the main memory is 3, 4 is not our target. This is our code execution results, the reason is less than 200,000.
Without volatile declaration process described object bytecodes

Before without volatile declaration, after entering the thread may not be getstatic command, the variable value changed, but threads do not know.
So, this is a plus

Fourth, the correct posture thread-safe

In talking about this, I think we should have no doubts about the results of the implementation of the above code.
But the problem again, how to ensure that the correct target to get it.

1, synchronized Almighty

Compared we see this keyword, you already know what I want to say the following.

 public synchronized static  void add(){
        i++;
    }

Target results for the add method, add the synchronized keyword modified after finally get, it is our target of 20,000.
Of course, the more universal, often represent a more incompetent.
The performance of this method is to use their own hand than be lock and unlock, the performance of a lot worse.
Especially in the jdk version 1.5, the performance difference is very large. But in subsequent jdk versions of synchronized gradually during optimization. And the government has also recommended this way, after all, than he ReentrantLock be elegant, coooooool lot.

2, high-performance ReentrantLock

private static  int i = 0;
    private static ReentrantLock lock = new ReentrantLock();
    
    public  static  void add(){
        lock.lock();
        try{
            i++;
        }finally {
            lock.unlock();
        }
    }

Even i ++, we have to be try, this is to develop good habits semantics = _ =
every lock, bound to be a unlocked. Otherwise .... Hey Hey
It should be noted, ReentrantLock (reentrant lock) than the synchronized, more than other advanced features, wait for interruptible achieve fair locks, as can bind multiple conditions. Here is not to carry out discussions.

3, narrow AtomicInteger

 private static AtomicInteger i =new AtomicInteger(0);
    public  static  void add(){
        i.addAndGet(1);
    }

Atomic objects are many, such as AtomicBoolean, AtomicLong and so on.
He assured the atomic data operations, realization of the principle is the principle by CAS.
What is CAS? I.e., Compare and Swap:
acquiring a main memory value (A), the acquired value (A) with the new value (B) into parameters. Here its value is obtained, if consistent with the value obtained transmission value A, to modify the value of the new value of the main memory B.
This is the CAS
course in achieving Atimic in, or use the Unsafe class, he can directly manipulate the physical memory! ! ! !
Here we are not his exact start on.

V. Summary

Memory model divided into working memory with the main memory.
In fact, say so meaningless, I put it another way, why should distinguish between working memory and main memory? ?
A thread is the basis of the program is running, and thread needs to exchange data with the computer, but due to the composition of the computer, data exchange will be some memory zone transfers faster, some slower transmission. But also to ensure the security of the data, we distinguish between a main memory (will be understood narrowly as physical memory) and working memory (i.e. cache register, when the amount of time, also stored in the physical memory)

When revisit JVM, many times I was thinking why? That is why such a design, so what good design, a lot of revenue.

Sixth, reference

"In-depth understanding of the Java Virtual Machine"

Reproduced in: https: //www.cnblogs.com/xuyuanpeng/p/11098601.html

Guess you like

Origin blog.csdn.net/weixin_30612769/article/details/94953405