Original address:www.cnblogs.com/chihirotan/…
Start by reading the Java memory model (as distinguished from the JVM’s memory model, heap, stack, workspace)
The Java memory model is used to screen out the memory differences of various hardware and operating systems to achieve cross-platform memory access effect. JLS(Java Language Specification) defines a unified Memory management Model (JMM)
The Java memory model specifies that all variables are stored in main memory, which is just a portion of the virtual machine’s memory, which is just a portion of the computer’s physical memory (the portion allocated for virtual machine processes).
The Java memory model is divided into primary memory and working memory. Main memory is shared by all threads, while working memory is one for each thread and is not shared.
Each thread also has its own working memory, which holds a main memory copy of variables used by the thread. All operations (reads, assignments) by a thread to a variable must be performed in working memory, rather than directly reading or writing variables in main memory. Different threads cannot directly access variables in each other’s working memory, and the transfer of variable values between threads needs to be completed through main memory. The interaction among threads, main memory and working memory is shown as follows:
Java memory interaction
JLS defines the operation instructions for main memory: Lock, unlock, read, load, use, assign, Store, and write. Read -load copies variables from main memory to current working memory, use-assign executes code to change shared variable values, and store-write refreshes main memory with working memory data.
- Read: Acts on a main memory variable, transferring the value of a variable from main memory to the thread’s working memory for subsequent load action
- Load: Variable acting on working memory, which puts the value of the variable obtained from main memory by the read operation into a copy of the variable in working memory.
- Use: variable applied to working memory, passing the value of a variable in working memory to the execution engine. This operation is performed whenever the virtual machine reaches a bytecode instruction that requires the value of the variable to be used.
- Assign: a working memory variable that assigns a value received from the execution engine to the working memory variable. This operation is performed whenever the virtual machine accesses a bytecode instruction that assigns a value to the variable.
- Store: Variable applied to working memory that transfers the value of a variable in working memory to main memory for subsequent write operations.
- Write: a variable operating on main memory that transfers store operations from the value of a variable in working memory to a variable in main memory.
Why multithreading is necessary (to make the most of your CPU)
For example, let’s say I need 10,000 pieces of data right now, which would take 100 minutes. If it is a single-threaded serial operation, it takes 100 minutes. So if you have 10 threads running at the same time, and each thread runs 100 pieces of data, you can do it all in 10 minutes. (In short, make full use of physical resources CPU)
Three features of multithreading
Atomicity means that an atomic operation in the CPU cannot be paused and then scheduled without being interrupted, completed, or not executed at all. Atomic manipulation guarantees atomicity.
X ++ (contains three atomic operations) a. Fetch the value of variable x and put it in register b. C. Assign the value in the register to x
Atomic variable operations directly guaranteed by the Java memory model include read, load, use, assign, Store and write. It can be roughly considered that access and read and write of basic data types are atomic. If a wider atomicity guarantee is needed, the Java memory model also provides for lock and UNLOCK operations to meet this requirement, although the virtual machine does not make lock and UNLOCK operations available to users directly. It does, however, provide higher-level bytecode instructions monitorenter and Monitorexit to implicitly use these two operations. These bytecode instructions are reflected in Java code as synchronized blocks, Thus, operations between synchronized blocks are also atomic.Copy the code
2. Visibility
The main and working memory of the Java memory model solves the visibility problem. Volatile makes variables visible — it prevents the compiler from optimizing a member variable by forcing it to re-read its value from memory every time it is accessed by a thread. Furthermore, when a member variable changes, the thread is forced to write the changed value back to shared memory, so that two different threads always see the same value of a member variable at any time, which ensures visibility.
Visibility means that when one thread changes the value of a thread-shared variable, other threads are immediately aware of the change. This is true for both plain and volatile variables, which differ from volatile variables in that the special rules of volatile ensure that new values are immediately synchronized to main memory and flushed from memory immediately before use. We can say that volatile guarantees visibility of variables during thread operations, whereas normal variables do not.Copy the code
The natural Ordering of a program in the Java memory model can be summed up as follows: if you observe it within a thread, all operations are ordered. If you observe another thread in one thread, all operations are unordered. The first part of the sentence refers to the phenomenon of “instruction reordering” and “main-main-memory synchronization delay”.
Thread state
1. New state (New) : a New thread object is created. 2. Runnable: After a thread object is created, another thread calls its start() method. The thread in this state is in the runnable thread pool and becomes runnable, waiting to acquire CPU usage. 3. Running: The thread in the ready state grabs the CPU and executes the program code. 4. Blocked: Blocked is when a thread gives up CPU usage for some reason and temporarily stops running. Until the thread enters the ready state, it has no chance to go to the running state. There are three types of blocking: Wait blocking: A running thread executes wait(), and the JVM places the thread in the wait pool. (2) Synchronous blocking: When a running thread acquires a synchronized lock on an object, if the lock is occupied by another thread, the JVM adds that thread to the lock pool. Other blocking: When a running thread executes a sleep() or join() method, or makes an I/O request, the JVM puts the thread in a blocked state. When the sleep() state times out, when the join() wait thread terminates or times out, or when I/O processing is complete, the thread goes back to the ready state. 5. Dead: a thread terminates its life cycle when it finishes executing or exits the run() method due to an exception.
Multithreading safety
synchronized
The Synchronized keyword guarantees data read and write consistency and visibility, but it is a blocking thread control method. During the use of the keyword, all other threads cannot use this variable, which leads to a requirement for controlling thread safety called non-blocking synchronization. (The synchronization mechanism uses a “time for space” approach.)
volatile
The Java language specification states that, for best speed, threads are allowed to keep a private copy of a shared member variable and compare it to the original value only when the thread enters or leaves a synchronized code block. When multiple threads interact with an object at the same time, attention must be taken to keep the threads informed of changes in shared member variables. The volatile keyword tells the VM not to keep a private copy of the member variable, but to interact directly with the shared member variable. Usage suggestion: Use volatile on member variables accessed by two or more threads. Do not use it when the variable to be accessed is already in a synchronized block or is a constant. Use of volatile is inefficient because it blocks out necessary code optimizations in the VM, so be sure to use this keyword only when necessary. As in C, the compiler is prohibited from optimizing ~~~~
ThreadLocal
ThreadLocal is not designed to solve the problem of multiple threads accessing shared variables. Instead, it creates a separate copy of variables for each thread, providing a way to hold objects and avoiding the complexity of passing parameters.
As the name implies, it is a local variable. Its function is very simple, is to provide a copy of the variable value for each thread using the variable, so that each thread can independently change its own copy, without conflict with other threads copy. From the thread’s point of view, it is as if each thread owns the variable completely. (ThreadLocal uses a “space for time” approach.)
Special types of Long and Double 64Bit
Volatile does not provide atomicity beyond simple operations on long and double. So even if you make a volatile variable volatile, the operation on that variable is not atomic, and you can’t avoid errors in a concurrent environment!
Java memory model Lock, unlock, read, load, assign, user, Store, and write operations are atomic, but the Java memory model divides read and write operations of 64-bit data that are not volatile into two 32-bit operations. Multithreading concurrency, there will be a thread may read the value of “half a variable”, however, this situation is very rare, commercial virtual machines of all platforms almost choose to 64-bit read and write as atomic operation to achieve the standard.
Java memory size
- -xms Specifies the memory allocated for JVM startup. For example, -xms200m indicates that 200M is allocated
- -xmx Specifies the maximum memory allocated for the RUNNING OF the JVM. For example, -xms500m indicates that the JVM process can occupy a maximum of 500M memory
- -Xss Specifies the size of memory allocated for each thread started by the JVM. The default is 256K in JDK1.4 and 1M in JDK1.5+
\
Note: Explain multithreading
1. As a high-level language, Java language supports multi-threaded operations, mainly to solve the efficiency problem caused by single-thread blocking, but also to make full use of the advantages of multi-core CPU. Using multiple threads also presents problems. How do threads communicate with each other? How do threads synchronize with each other?
2. Communication between threads is realized by calling shared memory and thread methods. In the multithreaded system, The Java memory model is divided into main memory and shared memory. Through the data exchange between memory, the communication between threads depends on the visibility of multithreading. Threads have basic state, and the communication between threads can also be realized by actively calling wait and notify methods of threads.
3. Thread synchronization is also a problem caused by concurrent threads manipulating shared variables. Multithreading allows the use of synchronize, volatile, and ThreadLocal to ensure the security of multithreading. Synchronize is a heavy-duty lock that blocks a single thread and causes no concurrent operation for updating variables, greatly reducing system performance. Volatile is a lightweight atomic lock that must interact with main memory every time a volatile variable is read or written. It prohibits some reordering optimizations by the compiler and processor.