Abstract: Atomicity refers to the ability of one or more operations to execute in a CPU without interruption. Atomic operations, once started, continue until the end of the operation without interruption.
This article is shared by Huawei cloud community “[High Concurrency] Decryption leads to the second dark hand behind the concurrency problem — atomic problem”, author: Glacier.
atomic
Atomicity is the ability to execute one or more operations on the CPU without interruption. Atomic operations, once started, continue until the end of the operation without interruption.
We can also think of atomicity as a series of operations performed by a thread, which are executed as an indivisible whole, all or none of the operations are executed, and there is no such thing as a partial execution. This is called atomicity.
A typical scenario of atomic operation is transfer. For example, if both Xiaoming and Xiaogang have a balance of 200 yuan, Xiaoming transfers 100 yuan to Xiaogang. If the transfer succeeds, Xiaoming’s account balance is 100 yuan and Xiaogang’s account balance is 300 yuan. If the transfer fails, the balance of Xiao Ming and Xiao Gang’s account is still 200 yuan. There can’t be a situation where the Ming account is $100 and the gang account is $200, or the Ming account is $200 and the gang account is $300.
Here, the operation of transferring 100 yuan from Xiao Ming to Xiao Gang is an atomic operation, which involves the operation of reducing the balance of Xiao Ming’s account by 100 yuan and increasing the balance of Xiao Gang’s account by 100 yuan. The two operations are an inseparable whole, and either all of them will be executed or none of them will be executed.
If the transfer from Xiaoming to Xiaogang is successful, it is as follows.
If the transfer from Xiaoming to Xiaogang fails, it is as follows.
You’re not going to get 100 dollars for Ming and 200 dollars for Gang.
You don’t get 200 for Xiaoming and 300 for Xiaogang.
thread
In concurrent programming, the number of threads is often greater than the number of cpus, and each CPU can only be used by one thread at a time. The ALLOCATION of CPU resources adopts the time slice rotation strategy, that is, each thread is allocated a time slice, and the thread occupies CPU resources to execute tasks in this time slice. When a thread that occupies CPU resources completes a task, it frees CPU resources for other threads to run. This is called task switching, also known as thread switching or thread context switching.
If you still don’t understand, we can use the following diagram to simulate the process of thread switching in the CPU.
There are threads in the picture A and B two threads, thread in the thread and thread B every little squares represent the threads occupy CPU resources and perform the task, the little square of time, called time slice, at this time, occupy CPU threads are executed on the CPU, does not occupy CPU thread will not be executed on the CPU. Each dotted line indicates that the thread is not using CPU resources. The CPU switches frequently between threads A and B.
Atomicity problem
Once you understand what atomicity is, the problem of what atomicity is is easier.
Atomicity is when one or more operations are interrupted during execution in the CPU.
Atomic problems can occur when a thread is performing an operation and the CPU switches to another task, interrupting the operation being performed by the current thread.
If you still don’t understand, let’s take an example: suppose you are in a line up bank to handle the business, xiao Ming in front of you, the counter clerk for xiao Ming to handle business, just to you, the bank off work at this time, the counter salesman smile and tell you: really sorry, Sir (madam), we are off work, you come back tomorrow! At this point, you are just like a thread that occupies CPU resources, and the clerk of the counter is the CPU that has a thread switch, she will switch the thread to go off work this thread, the operation to go off work.
Atomicity issues in Java
In Java, the concurrent program is based on multi-threading technology to write, which will also involve the CPU for the thread switch problem, it is the TASK switch mechanism in THE CPU, resulting in the concurrent programming will appear atomic strange problem, and atomic problem, has also become the second “black hand” leading to the concurrent problem.
In concurrent programming, a simple statement in the Java language will correspond to multiple instructions in the CPU. Suppose we write the code for the ThreadTest class as follows.
package io.mykit.concurrent.lab01; /** * @author binghe * @version 1.0.0 * @description */ public class ThreadTest {private Long count; public Long getCount(){ return count; } public void incrementCount(){ count++; }}Copy the code
Next, open the directory where the class file of the ThreadTest class resides and enter the following command on the CMD command line.
javap -c ThreadTest
Copy the code
The following results are obtained, as shown below.
d:>javap -c ThreadTest
Compiled from "ThreadTest.java"
public class io.mykit.concurrent.lab01.ThreadTest {
public io.mykit.concurrent.lab01.ThreadTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.Long getCount();
Code:
0: aload_0
1: getfield #2 // Field count:Ljava/lang/Long;
4: areturn
public void incrementCount();
Code:
0: aload_0
1: getfield #2 // Field count:Ljava/lang/Long;
4: astore_1
5: aload_0
6: aload_0
7: getfield #2 // Field count:Ljava/lang/Long;
10: invokevirtual #3 // Method java/lang/Long.longValue:()J
13: lconst_1
14: ladd
15: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
18: dup_x1
19: putfield #2 // Field count:Ljava/lang/Long;
22: astore_2
23: aload_1
24: pop
25: return
}
Copy the code
Here, we focus on the CPU instructions corresponding to the incrementCount() method, as shown below.
public void incrementCount();
Code:
0: aload_0
1: getfield #2 // Field count:Ljava/lang/Long;
4: astore_1
5: aload_0
6: aload_0
7: getfield #2 // Field count:Ljava/lang/Long;
10: invokevirtual #3 // Method java/lang/Long.longValue:()J
13: lconst_1
14: ladd
15: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
18: dup_x1
19: putfield #2 // Field count:Ljava/lang/Long;
22: astore_2
23: aload_1
24: pop
25: return
Copy the code
You can see how many CPU instructions correspond to just a few lines of incrementCount() in the Java language. These CPU instructions can be roughly divided into three steps.
-
Instruction 1: CPU register that loads the variable count from memory.
-
Instruction 2: perform count++ operation in register.
-
Instruction 3: Write the result to the cache (either CPU cache or memory).
When the operating system performs a thread switch, it may occur after any CPU instruction completes, rather than after a statement in a program. If A thread switch occurs after thread A executes instruction 1 and both threads execute count++, the result is 1 instead of 2. Here, we can use the following figure to represent this process.
From the figure above, we can see that A thread switch occurred after thread A loaded count=0 into the CPU register. Thread B loads count=0 into the register, performs count++, and writes count=1 to memory. At this point, the CPU switches to thread A. After the count++ operation in thread A, the count value in thread A is 1, and thread A writes count=1 to memory. At this point, the count value in memory is 1.
So, if there are threads executing in the CPU at the same time that a thread switch occurs in the CPU, it can cause atomicity problems, which is one of the root causes of frequent problems in concurrent programming. Only when we fully understand and master the atomicity of threads and the root causes of the atomicity problems, and pay attention to whether there are atomic problems in the concurrent programs written in daily work, can we write concurrent programs better.
conclusion
Visibility problems with caching, atomicity problems with thread switching, and orderliness problems with compilation optimizations are the three sources of frequent weird problems in concurrent programming. Visibility problems with caching and atomicity problems with thread switching have been described. In the next article, we continue to delve into the problem of order in high concurrency.
Click to follow, the first time to learn about Huawei cloud fresh technology ~