Atomic operation class related to thread concurrency

#Thread concurrent atomic operation class

What is atomicity is that the operation is completed at one time. When operating variables, other threads cannot operate variables, that is, the role of the synchronized synchronization keyword we mentioned earlier. In this section, instead of synchronized, we use the atomic classes in the system API. Today, we take one of the AtomicInteger classes as an example to explain.

For example, we have 20 people selling tickets at the same time, each selling 1000 tickets. How many tickets did we sell in the end? Here's the answer: 20000.
Let's see how to write the code. 20 people are equivalent to 20 threads, and then each thread has 1000 for loops, adding 1 to the number of votes each time. Then the java code is:

Simulate 20 people selling tickets together

public class ThreadAtomicTest {

	static int ticketNums = 0; //Final votes

	public static void main(String[] args) {

		for(int i = 0; i < 20; i++){
		new Thread(new Runnable(){

			public void run() {
				for(int i = 0; i < 1000; i++){
					ticketNums++ ;
				}
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
		}
		
		while (Thread.activeCount() > 1) {
            Thread.yield();
        }

		System.out.println("ticketNums="+ticketNums);
	 }

 } //Class end

Code analysis:

The new Thread generates a thread. The for loop in the run method is 1000 times, which means that one person sells 1000 tickets, and then the peripheral for loop is 20 times, which means that 20 people sell tickets at the same time, that is, 20 threads
Representing 20 conductors. Finally, system Out outputs the total number of tickets sold. The while loop is used to prevent the main thread from ending. Otherwise, the main function will be executed quickly, and the sub thread will be executed before it is finished
Quit.

After running for 3 times, the result is not 20000, which indicates that there is a problem. The number of printed votes is as follows:

ticketNums=18434
ticketNums=17564
ticketNums=16596

Why? The reason is that there is no synchronization lock in the line of ticketNums +=1. For example, when the first thread executes to ticketNums + +, it reads out the initial value 0 of ticketNums. At this time, thread 2 also reads out the initial value 0 of ticketNums before thread 1 finishes executing the + + operator. Finally, both threads perform the + + operator on 0. The final result of thread 1 + + is 1 and the result of thread 2 + + is 1. They should have sold two tickets, As a result, the number of votes was 1, one less. Similar to this, multithreads rush to operate on public variables (critical resources), resulting in asynchrony. Then, the key to solve this problem is to synchronize threads. When one thread operates variable + +, other threads cannot intervene. Let me use synchronized to realize it first.

The java code is as follows (use synchronized to realize the atomicity of operation variables)

public class ThreadAtomicTest {

	static int ticketNums = 0;

	public static void main(String[] args) {
		for(int i = 0; i < 20; i++){
			new Thread(new Runnable(){

				public void run() {
					for(int i = 0; i < 1000; i++){
						synchronized (ThreadAtomicTest.class){
						    ticketNums++;	
						}
					}
					try {
						Thread.sleep(5);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
		while (Thread.activeCount() > 1) {
            Thread.yield();
        }
		System.out.println("ticketNums="+ticketNums);
	}

} //Class end

Code analysis:
This time, we added the synchronized synchronization lock keyword to the periphery of ticketNums + +. The lock here uses the bytecode of a class. Of course, we can also use a static object as a lock, as long as we ensure that each thread uses the same lock object. The final number of votes is 20000, correct!

Next, we use today's AtomicInteger class to achieve the above synchronized effect. I know that AtomicInteger is an atomic operation without looking at the word. It is specially used to operate int values. It can control the operation of ticketNums + + at one go before allowing other threads to operate ticketNums We implement this by calling the incrementAndGet function class of AtomicInteger. The specific code is as follows:

java uses AtomicInteger to control variables in multithreading++

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadAtomicTest {
	static AtomicInteger ticketNums = new AtomicInteger(0);
	public static void main(String[] args) {
		for(int i = 0; i < 20; i++){
			new Thread(new Runnable(){
	
				public void run() {
					for(int i = 0; i < 1000; i++){
						ticketNums.incrementAndGet();
					}
					try {
						Thread.sleep(5);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
		while (Thread.activeCount() > 1) {
            Thread.yield();
        }

	  System.out.println("ticketNums="+ticketNums.get());
	}

}

Code parsing
static AtomicInteger ticketNums = new AtomicInteger(0);new is an atomicinteger object. The int value stored in it is initially 0. Then, call ticketnums in the multi-threaded run() method incrementAndGet(); Indicates that the int value is + + and the current value is returned. The most important thing is that it is not disturbed by other threads. It is an atomic operation executed at one go.

OK, that's all for today.

Keywords: Java Back-end

Added by Gruzin on Sun, 30 Jan 2022 20:30:49 +0200