Java atomic classes are not many, the package path is located in: java.util.concurrent.atomic, roughly the following classes:
Java.util.concurrent.atomic.AtomicBooleanjava.util.concurrent.atomic.AtomicIntegerjava.util.concurrent.atomic.AtomicInteg erArrayjava.util.concurrent.atomic.AtomicIntegerFieldUpdaterjava.util.concurrent.atomic.AtomicLongjava.util.concurrent.at Omic. AtomicLongArrayjava.util.concurrent.atomic.AtomicLongFieldUpdaterjava.util.concurrent.atomic.AtomicMarkableReferencejava . util.concurrent.atomic.AtomicReferencejava.util.concurrent.atomic.AtomicReferenceArrayjava.util.concurrent.atomic.Atomic ReferenceFieldUpdaterjava.util.concurrent.atomic.AtomicStampedReferencejava.util.concurrent.atomic.DoubleAccumulatorjava . util.concurrent.atomic.DoubleAdderjava.util.concurrent.atomic.LongAccumulatorjava.util.concurrent.atomic.LongAdder
Normal self-increment (value++ or value--) operations are non-atomic operations, but the use of atomic packaging for self-increment and decrement operations guarantees atomicity.
Test code:
PackageCom.demo;ImportJava.util.concurrent.atomic.AtomicInteger; Public classTestatomicinteger { Public StaticAtomicinteger value =NewAtomicinteger (0);//Atomic class Instances//public static int value = 0; Public Static voidMain (string[] args) { for(inti=0;i<100;i++){ NewThread () { Public voidrun () { for(intj = 0; J < 100; J + +) {value.incrementandget ();//value++; } }; }.start (); } while(Thread.activecount () >1)//ensure that the previous threads are finished executingThread.yield (); System.out.println (value); }}
This is a classic example of a thread-safe implementation of multithreaded access to shared variables.
If the two code of the comment is public, static int value = 0, and value++, and the corresponding code is replaced, a thread-safe problem occurs, even if the value variable is guaranteed to be visible with a volatile modifier, but because the value++ itself is non-atomic, The thread is still unsafe.
The main point is to explore the implementation process of ensuring atomic operation.
First, the Atomicinteger class introduces the Unsafe class, and the path of the class is Sun.misc.Unsafe. In fact, most of the atomic classes above import the class.
Inside the Atomicinteger class, an instance of unsafe is referenced by an unsafe type of statically immutable variable unsafe.
Private Static Final unsafe unsafe = unsafe.getunsafe ();
The Atomicinteger class then saves its own value with value and is provided externally with the Get () method.
Private volatile int value; Public Atomicinteger (int initialvalue) { = initialvalue;} ... /** @return*/publicfinalint get () { return value;}
With the above premise, continue down
Atomicinteger class of Incrementandget () method source code is as follows:
/*** atomically increments by one of the current value. * * @returnThe updated value*/ Public Final intIncrementandget () { for (;;) { intCurrent =get (); intNext = current + 1; if(Compareandset (current, next))returnNext; } }
Current holds the value, which is later used as the basis for whether another thread has changed the value. If no other thread is changing the value, the value that is expected to be fetched at the forward two points in time should remain unchanged. Next saves the value since increment 1, which is a value that may be updated to values if Compareandset (current, next) returns True, self-increment succeeds. If the return is false, indicating that the setting is unsuccessful, the other thread may have changed the shared variable, causing the current to fail, and then start the cycle again.
The source code of Compareandset () is as follows:
Public Final boolean compareandset (intint update) { return Unsafe.compareandswapint (This, Valueoffset, expect, update); }
The Compareandswapint () method of the unsafe object is called directly, and once again the method is traced:
The method is located in the Sun.misc.Unsafe class:
/** * atomically update Java variable to <tt>x</tt> if it is currently * Holding <TT>EXPECTED&L T;/tt>. @return <tt>true</tt> If successful */ Public Final native Boolean Long Offset, int expected, int x);
The method is found to be the native method.
And these methods, such as Compareandswapint (), Compareandswaplong (), Compareandswapobject (), are handled specially by the inside of the virtual machine, The result of the immediate compilation is a platform-related processor CAS (compare-and-swap) directive that cannot even be represented by JAVAP parsing bytecode.
It can be seen that the self-increment operation implemented by the atomic class can ensure that the root cause of atomicity lies in the support of the relevant instruction of the hardware (processor). This is accomplished by using a single instruction to perform the semantics of a multi-step operation, which the CAS directive can achieve.
The CAS directive requires three operands: memory location, old expected value, and new value. CAS requires that when and only if the value at the current memory location is equal to the old expected value, the value at the current memory location is updated with the new value, otherwise it does not perform the update operation, and the entire process maps the concept of a comparison-interchange (or comparison-update), and the process is an atomic operation.
If a parameter corresponds, the CAS directive requires three operands: (memory location, old expected value, and new value) to correspond to the last three parameters of the Compareandswapint () method, respectively: (Long offset,int expected,int x). The expected here is also the value of current, and X is the value of next.
Of course, there is an "ABA" problem in the atomic operation of the CAS directive, even if, when a thread is ready for detection, if other threads have changed the value of a shared variable several times and then returned to the initial value, the thread will be detected by CAs that the shared variable has not changed. This is not in accordance with the actual situation.
Line Shuo are all non-blocking (compared to the Synchronized keyword) through atomic classes. Its basic idea is based on conflict detection and cyclic retry. Specifically, the need to modify the shared data, the target operation is not locked first, if there are other threads found to make changes to the same shared data (corresponding to the current memory location to detect the value and the old expected value), then discard this modification, rewrite the loop again detect and try to modify until successful.
The time of Synchronized keyword embodies the strategy thought of pessimistic lock, and the realization of atom class embodies the thought of optimistic lock.
Off Topic:
The unsafe class mentioned above cannot be loaded and instantiated directly by the user source program, because its constructor is limited to unsafe class private, and unsafe only provides an instance of Getunsafe () interface indirectly providing unsafe, but even so, Getunsafe () Method is still quite harsh on callers ' requirements:
@CallerSensitive publicstatic Unsafe Getunsafe () { Class<? > caller = reflection.getcallerclass (); if (! Vm.issystemdomainloader (Caller.getclassloader ())) Throw New SecurityException ("Unsafe"); return theunsafe; }
The Issystemdomainloader (loader) method in the Sun.misc.VM class returns true only if the parameter loader is the bootloader.
/** * Returns True if the given class loader is in the system domain * and which all permissions are granted. * /publicstaticboolean issystemdomainloader (ClassLoader Loader) { returnnull; }
In combination with the above two methods, it is common that the loader of our user program is the application loader, and calling unsafe directly will throw an exception.
End ~ ~ ~
Reprint please specify the original address: http://www.cnblogs.com/qcblog/p/7750388.html
Resources:
1. In-depth understanding of Java Virtual machines: JVM advanced features and best practices
A summary of the implementation principle of Java Atom class Atomicinteger