Let’s get right to the point.

Let’s start with the memory model

In the CPU execution program, the temporary data of the program is stored in the main memory (that is, our memory RAM), and the CPU executes instructions faster than the reading and writing speed of the main memory. If the data is read and write to the main memory in time, the execution speed will be greatly reduced, so there is a cache in the CPU. When a program executes, it copies the data needed for an operation from main memory to the CPU’s cache, so that the CPU can read and write data directly from its cache while performing a calculation, and then flush the data from the cache to main memory when the operation is complete.

For example: I = I +1; When the CPU executes this code, it copies the value of I from main memory to the cache, increments I by one, writes the data to the cache, and writes the latest value of I from the cache to main memory.

Actually a more accurate picture:

  • If you have two CPU cores, each of which creates a thread, and execute the line I = I +1, will the value of I end up being 2?

Answer: Not sure. A: If thread1 in CPU1 executes, it fetches I from main memory and places it in its cache, then performs +1, stores the result in CPU1’s cache, and then flusher the result into main memory, where I =1. Thread2 in cpu2 does the same thing. Cpu2’s initial value of I is 0. The final result is still 1. This is called cache consistency.

  • Resolve cache consistency issues:

    1. Lock on the bus (a lock is a lock signal provided by a processor. When one processor outputs this signal on the bus, the requests of other processors will be blocked and the processor can monopolize the shared memory. Atomicity is guaranteed by bus locking). Disadvantages: add bus lock, although solve the problem, but will block other CPU execution, low efficiency.

    2. Cache consistency protocol. (When a CPU writes data, if it finds that the variable is a shared variable, that is, a copy of the variable exists in the caches of other cpus, it sends a signal to inform other cpus to set the variable’s cache line to invalid state and write data only after receiving an acknowledgement message from other cpus. When another CPU needs to read this variable and finds that its cache line is invalid, it will read it again from main memory.

  • Continue to raise the question: in the cache consistency issue, does the retrieval of data from main memory by other cpus have to be updated? The answer is not necessarily. Because the CPU needs to write data, the timing of flushing main memory is uncertain. This can only be done by locking (synchroized,lock, volatile, etc. In Java)

Three concepts of concurrent programming

Atomicity: Similar transactions

2. Visibility: Issues that cause cache consistency

3. Orderliness: Rearrangement of instructions is prohibited

JAVA memory model

Cause: Memory model is a set of specifications for multi-thread read and write operations in a shared memory system. This specification shields the differences in memory access between underlying hardware and operating systems, and solves the memory access problems caused by multi-level CPU cache, CPU optimization, and instruction rearrangement. In this way, Java programs (especially multithreaded programs) can access memory consistently on different platforms.

Within each thread, there is an internal block of working memory. This working memory holds a copy of the main memory shared data. And threads cannot access the working memory of other threads. (Tips: Thread working memory is an abstract representation of CPU registers and caches. It is not real.)

atomic

A. In Java, reads and assignments to variables of primitive data types are atomic operations. B. synchronized and Lock to ensure atomicity. 阿鲁纳恰尔邦Copy the code
Example: x = 10; // statement 1 y = x; // statement 2 x++; // statement 3 x = x + 1; // Only statement 1 is atomic. Statement 1 directly assigns 10 to x, and the thread executing this statement writes the value 10 directly to working memory. Statement 2 contains two steps, reading the value of x and then writing the value of x to the working memory. These two steps are atomic operations, but together they are not. Statement 3 and statement 4 contain three steps: read the value of x, add 1, and write to the working memory without atomicity.Copy the code
  • visibility

    A. synchronized or Lock to ensure visibility.

    B. Volatile ensures visibility.

    C. appens – before principle

A: Synchroized and Lock ensure that only one county obtains the Lock at a time and executes the synchronization code, flushing changes to main memory before releasing the Lock. So visibility is guaranteed. B: Shared variables that are volatile. If a thread changes the value of the variable, it forces the value to be written to main memory immediately and invalidates the variable in other threads. If other threads use the shared variable, they must obtain it from main memory. So it's also visible. C. Compliance with the happens-before principle ensures visibility between operations. Volatile invalidates variables in the working cache of other threads, but the data in main memory has not yet been updated. If volatile invalidates variables in the working cache of other threads, the data in main memory has not yet been updated. The answer is here: Volatile variable reads and writes are atomic, but other operations (such as increment) themselves are nonatomic.Copy the code
  • order

    In the Java memory model, the compiler and processor are allowed to reorder instructions, but the reordering process does not affect the execution of a single-threaded program, but affects the correctness of multithreaded concurrent execution. If there is no order reordering, there is no order problem.

    A. synchronized or Lock to ensure order.

    B. Volatile ensures order.

A. synchroized and Lock ensure that the internal code is executed by only one thread at a time. Single-thread instruction rearrangement is not a problem, so order is guaranteed. B. Volatile forbids command reordering, so orderliness can also be guaranteed.Copy the code

Happens-before principle

  • Sequence rule: In a thread, in order of code, operations written earlier take place before those written later
  • Lock rule: An unLock operation occurs first and a subsequent lock operation occurs with the same lock volume
  • Volatile variable rules: Writes to a variable occur first before reads to that variable occur later
  • Transfer rule: If operation A precedes operation B and operation B precedes operation C, it follows that operation A precedes operation C
  • Thread start rule: The start() method of the Thread object occurs first for each action of the Thread
  • Thread interrupt rule: A call to the threadinterrupt () method occurs before code in the interrupted thread detects the occurrence of an interrupt event
  • Thread termination rules: All operations in a Thread occur before the Thread terminates. Thread termination can be detected by the end of thread.join () method and the return value of thread.isalive ()
  • Object finalization rule: The finalization of an object occurs first at the beginning of its Finalize () method

If can’t meet the happens-before principle, you need to use synchroized, volatile, Lock, etc.

  • With the Java memory model, the FIG leaf for concurrent programming is lifted. The next article will explain synchroized, volatile, lock… Equal locking mechanism.