Atomic variable and non-blocking synchronization mechanism one, the disadvantage of the lock
1. Under Multi-thread: The lock hangs and restores the process to have the very big overhead (in time modern JVM will decide when to use hangs, when spins the wait)
2.volatile: Lightweight synchronization mechanism, but cannot be used to build atomic composite operations
Therefore: there needs to be a way to manage the competition between threads in a finer grained way, similar to the volatile mechanism, while also supporting atomic update operations
Second, CAS
An exclusive lock is a pessimistic technique-it assumes the worst case, so each thread is exclusive
CAS Compare and Exchange: Compareandswap/set (A, B): We think the memory value is a, if it is a, modify it to B, otherwise do not operate; Returns the original value at memory or whether the modification succeeded
Example: simulating CAS operations
//Simulation of CAs Public classSimulatedcas {Private intvalue; Public synchronized intget () {returnvalue; } //CAS Operations Public synchronized intCompareandswap (intExpectedvalue,intnewvalue) { intOldValue =value; if(OldValue = =expectedvalue) {Value=NewValue; } returnOldValue; } Public synchronized BooleanCompareandset (intExpectedvalue,intnewvalue) { return(Expectedvalue = =Compareandswap (Expectedvalue, newvalue)); }}//Typical usage Scenarios Public classCascounter {PrivateSimulatedcas value; Public intGetValue () {returnValue.get (); } Public intincrement () {intv; Do{v=Value.get (); } while{(v! = Value.compareandswap (V, v + 1)); } returnV + 1; }}
Java provides the operation of CAs
Atomic State Class: CAs method for atomicxxx
JAVA7/8: Operation of Map: Putifabsent, computerifabsent, computerifpresent ...
Third, the Atomic variable class
The Atomicrefence atom updates an object, which can be a custom object, such as:
Public classCasnumberrange {Private Static classIntpair {//invariant:lower <= Upper Final intLower//To define a value as an immutable domain Final intUpper//To define a value as an immutable domain PublicIntpair (intLowerintUpper) { This. Lower =Lower; This. Upper =Upper; } } Private Finalatomicreference<intpair> values =NewAtomicreference<intpair> (NewIntpair (0, 0));//Encapsulating Objects Public intGetlower () {returnvalues.get (). Lower; } Public intGetupper () {returnvalues.get (). Upper; } Public voidSetlower (inti) { while(true) {Intpair OLDV=Values.get (); if(I >oldv.upper) {Throw NewIllegalArgumentException ("Can ' t set lower to" + i + "> upper"); } Intpair NEWV=NewIntpair (i, oldv.upper);//property is an immutable domain, the new object is updated every time if(Values.compareandset (OLDV, NEWV)) {//Atomic Update, if the thread is modified during the process, the other threads will not be updated successfully because the OLDV and memory values are different return; } } } //Ibid . Public voidSetupper (inti) { while(true) {Intpair OLDV=Values.get (); if(I <oldv.lower)Throw NewIllegalArgumentException ("Can ' t set Upper to" + i + "< lower"); Intpair NEWV=NewIntpair (Oldv.lower, i); if(Values.compareandset (OLDV, NEWV))return; } }}
Performance issues: Using atomic variables in medium-low concurrency (competition) is faster than using lock speed, typically faster than lock speed
Four, non-blocking algorithm
Non-blocking algorithms can be used in many common data structures
Non-blocking algorithm: in multi-threading, the success of the work is uncertain, need to loop execution, and atomic operation through CAs
1, the above Casnumberrange
2, stack of non-blocking algorithm: Only save the head pointer, only one state
//non-blocking algorithm for stack implementation: one-way linked list Public classConcurrentstack <E>{atomicreference<Node<E>> top =NewAtomicreference<node<e>>(); Public voidpush (E item) {Node<E> Newhead =NewNode<e>(item); Node<E>Oldhead; Do{Oldhead=Top.get (); Newhead.next=Oldhead; } while(!top.compareandset (Oldhead, Newhead));//CAS operations: Atomic update operation, cyclic judgment, non-blocking } PublicE Pop () {Node<E>Oldhead; Node<E>Newhead; Do{Oldhead=Top.get (); if(Oldhead = =NULL) { return NULL; } newhead=Oldhead.next; } while(!top.compareandset (Oldhead, Newhead));//CAS operations: Atomic update operation, cyclic judgment, non-blocking returnOldhead.item; } Private Static classNode <E> { Public FinalE Item; PublicNode<e>Next; PublicNode (E item) { This. Item =item; } }}
3, the non-blocking algorithm of the list: Head and tail of fast access, save two states, more complex
Public classLinkedqueue <E> { Private Static classNode <E> { FinalE Item; FinalAtomicreference<linkedqueue.node<e>>Next; PublicNode (E item, linkedqueue.node<e>next) { This. Item =item; This. Next =NewAtomicreference<linkedqueue.node<e>>(next); } } Private Finallinkedqueue.node<e> dummy =NewLinkedqueue.node<e> (NULL,NULL); Private FinalAtomicreference<linkedqueue.node<e>> head =NewAtomicreference<linkedqueue.node<e>>(dummy); Private Finalatomicreference<linkedqueue.node<e>> tail =NewAtomicreference<linkedqueue.node<e>> (dummy);//Save Tail Node Public Booleanput (E item) {Linkedqueue.node<E> NewNode =NewLinkedqueue.node<e> (Item,NULL); while(true) {Linkedqueue.node<E> curtail =Tail.get (); Linkedqueue.node<E> Tailnext =CurTail.next.get (); if(Curtail = =Tail.get ()) { if(Tailnext! =NULL) { //in the middle state, update the tail node to the next of the current tail nodeTail.compareandset (curtail, tailnext); } Else { //set next to the current tail node as a new node: Linked list if(CurTail.next.compareAndSet (NULL, NewNode)) { /*** This is the middle state, although there are two atomic operations here, the whole is not atomic, but through the algorithm to ensure security: * cause is in the middle state, if there are other threads come in Operation, the above if will execute; * The above if operation is to help the current thread to complete the update tail node operation, and the current thread's update will fail to return, eventually the update succeeds*/ //The link succeeds, the tail node has changed, then the current tail node is set to the new nodeTail.compareandset (curtail, newNode); return true; } } } } }}
3. Atomic Domain Updater
The above logic realizes the non-blocking algorithm of the linked list, using node to save the head node and tail nodes
In the actual concurrentlinkedqueue, a reflection-based atomicreferencefiledupdater is used to wrap the node
V. the problem of ABA
Issues that are prone to CAS operations:
Determine whether the value is a, yes, continue to update the operation to change to B;
However, if a thread changes the value A to C and then changes back to a, the original thread will determine that a=a successfully performed the update operation;
If you change a to C and then back to a operation, you also need to consider the changes, you need to optimize the algorithm
FIX: Add version number, each update operation to update version number, even if the value is the same
Java Concurrency Programming (8) Atomic variables and non-blocking synchronization mechanisms