This is an interview with the United States, a problem, and later found that this is a common problem interview, blame yourself not fully prepared: i++; Is there a problem in a multithreaded environment? At that time the answer exists, then ask, how to solve? OK, I'll say lock or synchronized synchronization method. Then ask, is there a better way?
After some Baidu, Google, can also use Atomicinteger this class, this class provides self-increment, self-reduction and other methods (such as i++ or ++i can be achieved), these methods are thread-safe.
I. Complementary concepts
1. What is thread safety?
Java Concurrency in practice mentions that when multiple threads access a class, the class always shows the correct behavior, then the class is called thread-safe.
"Sync" in 2.Java
The main synchronization mechanism in Java is the keyword "synchronized", which provides an exclusive locking method, but the term "synchronization" also includes volatile type variables, explicit locks (Explicit Lock), and atomic variables.
2. atomicity
Atoms are the smallest units in the world and are indivisible. such as A=0; (a non-long and double type) This operation is indivisible, then we say this operation is atomic operation. Another example: a++; This operation is actually a = a + 1; is divisible, so he is not an atomic operation. There is a thread-safety problem with non-atomic operations, and we need to use synchronous technology (sychronized) to turn it into an atomic operation. An operation is an atomic operation, so we call it atomic. The Java concurrent package provides some atomic classes, and we can read the API to understand the use of these atomic classes. For example: Atomicinteger, Atomiclong, atomicreference and so on.
Ii. Examples of source code
1 Public classIncrementtestdemo {2 3 Public Static intCount = 0;4 Public StaticCounter Counter =NewCounter ();5 Public StaticAtomicinteger Atomicinteger =NewAtomicinteger (0);6 volatile Public Static intCountvolatile = 0;7 8 Public Static voidMain (string[] args) {9 for(inti = 0; I < 10; i++) {Ten NewThread () { One Public voidrun () { A for(intj = 0; J < 1000; J + +) { -count++; - counter.increment (); the atomicinteger.getandincrement (); -countvolatile++; - } - } + }.start (); - } + Try { AThread.Sleep (3000); at}Catch(interruptedexception e) { - e.printstacktrace (); - } - -System.out.println ("Static count:" +count); -System.out.println ("Counter:" +Counter.getvalue ()); inSystem.out.println ("Atomicinteger:" +Atomicinteger.intvalue ()); -System.out.println ("Countvolatile:" +countvolatile); to } + - } the * classCounter { $ Private intvalue;Panax Notoginseng - Public synchronized intGetValue () { the returnvalue; + } A the Public synchronized intincrement () { + return++value; - } $ $ Public synchronized intDecrement () { - return--value; - } the}
Output Result:
static count:995210000100009979
The first and last lines, each run, will have different results, but the results of the two rows are the same.
The above example shows that to solve the problem of the self-increment operation is unsafe in the multithreaded environment, you can choose to use the atomic class provided by Java, or use the synchronized synchronization method.
Using the volatile keyword does not resolve the non-atomic operation of thread safety. Volatile explanation
Third, the principle of self-amplification in Java
Although the increment operation ++i is a compact syntax that makes it look like an operation, the operation is not atomic, and it is not executed as an indivisible operation. In fact, it contains three separate operations: reads the value of count, adds a value of 1, and then writes the result to count. This is a "read-modify-write" sequence of operations, and its resulting state depends on the previous state.
Here is a simple class that uses the tool JAVAP in the JDK to decompile the Java bytecode file.
/**@author*/Publicclass testdemo { publicstaticint count; Public void code () { count+ +; }}
Localhost:increment zhengbinmac$ JAVAP-C Testdemo Warning: Binary file Testdemo contains increment.testdemocompiled from"Testdemo.java" Public classIncrement.testdemo { Public Static intcount; PublicIncrement.testdemo (); Code:0: Aload_01:invokespecial #1//Method java/lang/object. " <init> ":() V4:return Public voidcode (); Code:0:getstatic #2//Field count:i3: Iconst_14: Iadd5:putstatic #2//Field count:i8:return }
As in the bytecode, we find that the self-increment operation includes fetching numbers (Getstatic #2), plus one (iconst_1 and Iadd), saving (putstatic #2), which is not what we think of as a machine instruction.
Reference blog:
Atomic analysis of Java self-increment operation
How to ensure thread safety and primary key self-ordering in Java
Java-concurrency Atomic, synchronization and volatile
The atomicity and visibility of Java concurrency (i)
Java self-increasing atomicity problem (test volatile, Atomicinteger)