Java concurrency Programming 11. Atomic variable and non-blocking synchronization mechanism

Source: Internet
Author: User

There is no deadlock and other activity issues in the nonblocking algorithm.

In a lock-based algorithm, if a thread holds a lock while hibernating or spinning, other threads cannot execute, and the non-blocking algorithm is not affected by a single thread failure.

The disadvantage of the lock

Many JVMs optimize non-competitive lock acquisition and release operations, but if multiple threads request a lock at the same time, the JVM needs to take advantage of the operating system functionality. If this occurs, some threads will be suspended and resumed at a later time. When threads resume execution, they must wait for other threads to execute their time slices before they can be scheduled for execution. There is a significant overhead in the process of suspending and recovering threads, and there is usually a significant interruption in time. If a lock-based class contains fine-grained operations (such as a Synchronizer class that contains only a small amount of operations in most of its methods), the ratio of scheduling overhead to work overhead is very high when there is fierce competition in the lock.

In addition, when a thread is waiting for a lock, it cannot do anything else. If a thread is delayed by holding a lock, all threads that need the lock will not be able to proceed. If the blocked thread has a high priority and the thread holding the lock has a low priority, it will be a serious problem.

Compare and Exchange CAs

The CAS contains 3 operands---the memory location v to read and write, the value A to compare to and the new value B to write. When and only if the value of V equals A, CAS will update the value of V with the new value B atomically, otherwise no action will be taken. The value of V is returned regardless of whether the value of position v equals a.

CAS meaning: I think the value of V should be a, if so, then update the value of V to B, otherwise do not modify and tell the value of V is actually how much. CAS is an optimistic attitude, it wants to be able to perform the update operation successfully, and if another thread updates the variable after the last check, the CAS can detect the error.

/*** When multiple threads try to update the same variable simultaneously using CAS, only one of the threads can update the value of the variable, and the other threads will fail. * However, the failed thread is not suspended, but is told to fail in this competition and can try again. * Because a thread does not block when it competes with CAS, it can decide whether to retry, or perform some recovery operations, or not take any action. */ Public classSimulatedcas {Private intvalue;  Public synchronized intget () {returnvalue; }         Public synchronized intCompareandswap (intExpectedvalue,intnewvalue) {        intOldValue =value; if(OldValue = =expectedvalue) {Value=NewValue; }        returnOldValue; }         Public synchronized BooleanCompareandset (intExpectedvalue,intnewvalue) {        return(Expectedvalue = =Compareandswap (Expectedvalue,newvalue)); }}

The typical usage pattern for CAS is to first read the value a from V and calculate the new value B based on a and then atomically convert the value in V from A to B by CAs. because CAs detects interference from other threads, it is possible to implement atomic read-change-write operations even without using locks.
Non-blocking calculator

/*** Often, repeated retries are a reasonable strategy, but in some highly competitive situations, a better approach is to wait for a period of time or fallback before retrying, thus avoiding the problem of a live lock. * * Although the Java language's locking statements are relatively concise, the tasks that the JVM and operations need to do to manage locks are not simple. * When implementing a lock, it is necessary to traverse a very complex code path in the JVM and may cause operating system-level locks, thread hangs, and context-changing actions. * At best, it requires at least one CAs at a time of lock-up, so although CAs are not used when using locks, there is virtually no cost of execution. * In addition, executing CAS inside the program does not require the execution of JVM code, system calls, or thread scheduling operations. * The longer the code path appears at the application level, the shorter it actually becomes if you add code calls from the JVM and the operating system. * The main disadvantage of CAS is that it will enable callers to deal with competition issues while automatically handling competition issues in locks **/ Public classCascounter {PrivateSimulatedcas value;  Public intGetValue () {returnValue.get (); }         Public intincrement () {intv;  Do{v=Value.get (); } while(V! = Value.compareandswap (V, v + 1)); returnV + 1; }}

JVM Support for CAs

The underlying support is introduced in Java5.0, which exposes CAS operations on types such as Int,long and object references, and the JVM compiles them into the most efficient method provided by the underlying hardware. In atomic variable classes, these underlying JVM support is used to provide an efficient CAS operation for numeric types and reference types, while most classes in java.util.concurrent use these atomic variable classes directly or indirectly when implemented.

Non-blocking stacks

/**The stack is a linked list of node elements that are the top yop of the stack, and each element contains a value and a link to the next element. * The Push method creates a new node with the next field pointing to the current top of the stack and then using CAs to put the new node on top of the stack. */ 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)); }         PublicE Pop () {Node<E>Newhead; Node<E>Oldhead;  Do{Oldhead=Top.get (); if(Oldhead = =NULL){                return NULL; } newhead=Oldhead.next; } while(!Top.compareandset (Oldhead, Newhead)); returnOldhead.item; }    Private Static classNode<e>{         Public FinalE Item;  PublicNode<e>Next;  PublicNode (E item) { This. Item =item; }    }}

Non-blocking linked list

A linked list queue is more complex than a stack, and it must support fast access to both the head node and the tail node. It needs to maintain the head and tail pointers separately.

for a trailing insert, two points need to be updated: The next point of the current tail node points to the node to be inserted, and the tail node is updated to the newly inserted node. These two update operations require different CAS operations, which are not possible through atomic variables. Some strategies need to be used:

Policy one is to ensure that the data structure is always in a suppressed state, even in an update operation that contains multiple steps. Thus, when thread B arrives, if Discovery A is performing an update, thread B can know that an operation has partially completed and cannot immediately perform its own update operation. Then B can wait until the a completes the update. While it is possible for different threads to take turns accessing the data structure without causing damage, if one thread fails in the update operation, no other threads can be in the queue again.

Strategy Two is that if B arrives to find that a is modifying the data structure, then there should be enough information in the data structure so that B can complete a update operation. If B help a completes the update operation, B can perform its own operation without waiting for a to complete. When a recovers and then tries to complete its operation, it will find that B has done it for it.

/*** The key to implementation is: * When the queue is in a stable state, the next field of the non-node will be empty, and if the queue is in an intermediate state, then the Tail.next will be non-empty. * Therefore, any thread can get the current state of the queue by checking the tail.next. * Also, when the queue is in an intermediate state, you can end the insertion element operation that other threads are performing by moving the tail node forward by one node, which will return the queue to a stable state. */ Public classLinkedqueue<e> {    Private Static classNode<e>{        FinalE Item; FinalAtomicreference<node<e>>Next;  PublicNode (E item,node<e>next) {             This. Item =item;  This. Next =NewAtomicreference<node<e>>(next); }        Private Finalnode<e> dummy =NewNode<e> (NULL,NULL); Private FinalAtomicreference<node<e>> head =NewAtomicreference<node<e>>(dummy); Private Finalatomicreference<node<e>> tail =NewAtomicreference<node<e>>(dummy); Private Booleanput (E item) {Node<E> NewNode =NewNode<e> (Item,NULL);  while(true) {Node<E> curtail =Tail.get (); Node<E> Tailnext =CurTail.next.get (); if(Curtail = =Tail.get ()) {                    if(Tailnext! =NULL){                        //the queue is in the middle state, pushing the tail nodeTail.compareandset (curtail, tailnext); }Else{                        //in a stable state. Attempt to insert a new node                        if(CurTail.next.compareAndSet (NULL, NewNode)) {                            //Insert successful, try to push tail node, this step can be helped by another thread if it is not completedTail.compareandset (curtail, newNode); return true; }                    }                }            }        }    }}

ABA Issues
In some algorithms, if the value of V is first changed from a to B, then B becomes a.

The workaround is to update two values, including a reference and a version number, instead of updating the value of a reference. Atomicstampedreference and atomicmarkablereference Support performing atomic conditional updates on two of variables.

#笔记内容来自 " Java concurrency programming practice"

Java concurrency Programming 11. Atomic variable and non-blocking synchronization mechanism

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.