Research on Android multithreading (8) -- Understanding Atomicity in Java and multithreading in android
1. What is atomicity?
Atomicity is the smallest unit in the world and is severable. For example, if the = 0; (a is not of the long and double types) type, this operation is an atomic operation. For example, a ++ is actually a = a + 1; it is split, so it is not an atomic operation.
II. The role of atomic operations non-atomic operations will have thread security issues. We need to use the synchronization technology (sychronized) to turn it into an atomic operation. An operation is an atomic operation, so we call it atomic. The java. util. concurrent. atomic package provides the following atomic classes:
3. Understand the AtomicInteger class. Below are several common methods in the AtomicInteger class:
Many people may have the same question as me. How does AtomicInteger implement atomicity? Some predecessors have analyzed the source code of AtomiInteger, and I am only referencing it here to make a record. Let's take a look at the source code:
public final int getAndIncrement() {for (;;) {int current = get();int next = current + 1;if (compareAndSet(current, next))return current;}}
Looking at this code and the above analysis of atomicity, we can see from int next = current + 1 that it is difficult to ensure the atomicity of the operation here, focusing on the compareAndSet (current, next) method.
This function has only two parameters. Three values can be operated, namely value, exact CT, and update. It uses the hardware command CAS (compare and swap) to ensure its atomicity ).
The compareAndSet function ensures comparison. The assignment operation can be completed through an atomic operation.
Then, let's look at the entire function. All the code is put into a loop. If compareAndSet () fails to be executed, it indicates that after int current = get, the value is updated by other threads, so the current value is retained once until compareAndSet () is successfully executed.
In summary, the getAndIncrement () method is not an atomic operation. It only ensures that he and other functions are effective for value update. He uses an optimistic concurrency strategy based on conflict detection. As you can imagine, this optimism increases exponentially when the number of threads is very large.
4. Understand the volatile Modifier
In the Java memory model, there is main memory, and each thread also has its own memory (such as registers ). For performance, a thread maintains a copy of the variable to be accessed in its own memory. In this case, the value of the same variable may be different from the value of another thread's memory or the value in main memory at a certain moment.
If a variable is declared as volatile, it means that the variable is modified by other threads at any time, so it cannot be cached in the memory of the thread. The following example shows the role of volatile:
package com.codeing.snail.test;public class TestAtomic extends Thread {private volatile boolean pleaseStop;public void run() {while (!pleaseStop) {// do some stuff...}}public void tellMeToStop() {pleaseStop = true;}}
If pleaseStop is not declared as volatile and check its own copy when the thread executes run, it cannot be found that other threads have called tellMeToStop () to modify the pleaseStop value.
Volatile generally cannot replace sychronized, because volatile cannot guarantee the atomicity of operations. Even if it is just I ++, it is actually composed of multiple atomic operations: read I; inc; write I, if multiple threads execute I ++ at the same time, volatile can only ensure that the I they operate on is the same memory, but dirty data may still be written.
The volatile keyword is used to declare simple type variables, such as int, float, and boolean data types. If these simple data types are declared as volatile, their operations will change to atomic level. But there are some restrictions. For example, n in the following example is not atomic:
Package com. codeing. snail Il. test; public class TestAtomic extends Thread {public static volatile int n = 0; public void run () {for (int I = 0; I <10; I ++) try {n = n + 1; sleep (3); // latency of 3 ms} catch (Exception e) {}} public static void main (String [] args) throws Exception {Thread threads [] = new Thread [100]; for (int I = 0; I <threads. length; I ++) // create 100 threads [I] = new TestAtomic (); for (int I = 0; I <threads. length; I ++) // run the first thread threads [I] just created. start (); for (int I = 0; I <threads. length; I ++) // after all the 100 threads are executed, continue threads [I]. join (); System. out. println ("n =" + TestAtomic. n );}}
If the operation on n is atomic, the final output result should be n = 1000. When the area code is executed, n is usually less than 1000, this indicates that n = n + 1 is not an atomic operation. The reason is that the simple variable declared as volatile does not work if the current value is related to the previous value of the variable.
5. Use Cases of locks and Atomic
"The design atomic class is mainly used as a variety of blocks to implement non-blocking data structures and related infrastructure classes," JDK's documentation said. The compareAndSet () method is not a common replacement method for locking. It is applied only when an important update of an object is limited to a single variable. "compared with the lock, Volatile variables are also a very simple but fragile synchronization mechanism, in some cases, it will provide better performance and scalability than the lock. If you strictly follow the volatile usage conditions-that is, variables are truly independent from other variables and their previous values-in some cases, you can usevolatile
Replacesynchronized
To simplify the code. Howevervolatile
The code is often more error-prone than the code that uses the lock.
Atomicity is often mentioned in java multithreading. What is atomicity? Tutorial
Atomicity means that an operation cannot be paused and scheduled by the cpu midway through, that is, it cannot be interrupted, or it can be completed or not executed. if an operation is atomic, there will be no strange problems such as variable modification in a multi-threaded environment.
How can I Deeply Understand Java multithreading?
A thread is the smallest unit in System Scheduling because it consumes less resources than a process. Therefore, when similar tasks need to communicate with each other, all use threads for processing.
Only fixed one thing (for example: computing 1 + 2 + 3 +... + 9999999), the performance is not higher than the overall efficiency of using a single thread, because at the same time, so many operations are required. If multithreading is adopted, the system wastes some resources and time during thread scheduling, thus reducing the performance.
So does multithreading have no meaning? Of course not. Multithreading still has some value. When we write input stream output streams, write network programs, and so on, blocking will occur. If we do not use multithreading, when reading data from A, A is not ready, and the whole program is blocked, so nothing else can be done. If multithreading is used, you don't have to worry about this problem. Another example: in the game, if Role A and Role B use the same thread for processing, it is very likely that only the operations of Role A will be returned, the B role is always in use. In this way, it is definitely useless to play.
Therefore, the thread is useful, but it is not casually used. If it is used improperly, it may cause low performance. It is applicable to a specific extent. Generally, I think: we need to respond to multiple people and consider doing some things at the same time from the design perspective (these things may not have any relationship in many cases, or may have some relationships ).
When multithreading is used, if some threads are involved in resource sharing and mutual communication, you must pay attention to the thread security issue. Check whether the synchronized keyword is required based on the situation.