volatile、synchronized、ReentrantLock与CAS

部分摘自:

https://blog.csdn.net/zxh476771756/article/details/78685581

https://blog.csdn.net/tiandao321/article/details/80811103

一、JVM内存模型:

  ==JVM将内存组织为主内存和工作内存两个部分。==

  主内存主要包括本地方法区和堆。

  每个线程都有一个工作内存,工作内存中主要包括两个部分,一个是属于该线程私有的栈和对主存部分变量拷贝的寄存器(包括程序计数器PC和CPU工作的高速缓存区)。

  1. ==所有的变量都存储在主内存中(虚拟机内存的一部分)==,对于所有线程都是共享的。
  2. Each thread has its own working memory, working memory saved == the thread is to use a variable copy (the copy is a copy of the main memory variable) == thread all operations on the variables must be in the working memory, and not directly read and write main memory variables.
  3. Between == thread can not directly access each other's work == variables in memory, the threads are required to pass variables through the main memory to complete.

Here Insert Picture Description

Java Memory Model (JMM) defines the jvm main memory, main memory is shared by multiple threads . When a new object, it is to be allocated in main memory, a copy of some of the objects of each thread has its own working memory, working memory stores the main memory.

So there may be such a case: When you change the value of thread 2 xxx variables, but not enough time to write main memory among threads 2 turn to do other things, then thread 1 thread 2 because they do not know already variable xxx changes therefore will loop forever.

Two, volatile keyword

== java in volatile solve the visibility problem ==

  volatile that represents someone or something is unstable and volatile .

1, volatile memory to ensure visibility.

    Visibility is when a thread changes the value of shared variables, other threads can be aware of this change immediately.

    == difference between ordinary variable and volatile variables are: ==  

    Special rules == volatile guarantee new value can be immediately synchronized to the main memory , and every time immediately flushed from main memory before use . ==

2, can prohibit instruction reordering

So volatile to ensure the orderly to a certain extent.

    1) When the program executes a read operation or write operation volatile variables, change in front of the entire operation has been affirmative, and the result is already visible on the back of operation; operation in its rear certainly not performed;

    2) During instruction optimization can not be performed in place behind the statement of access to volatile variables, nor can the volatile variables back into the front statement execution.

  Example 1:

//x、y为非volatile变量

//flag为volatile变量

x = 2;        //语句1

y = 0;        //语句2

flag = true;  //语句3

x = 4;         //语句4

y = -1;       //语句5

  Since the volatile flag variable is a variable, then the reordering process is performed in the instruction, it does not put the statement 3 statement 1, 2 in front of the statement, the statement does not speak into 3 statement 4, 5 behind the statement. But be careful sequence of statements 1 and 2 of the statement, sequential statements 4 and 5 of the statement is not any guarantee.

  And the volatile keyword guarantees, 3:00 to execute the statement, the statement 1 and statement 2 must be finished up, and the results of a statement and statement of 2 to 3 statement, statement 4, 5 statement is visible.

  Example 2:

//线程1:

context = loadContext();   //语句1

inited = true;             //语句2

//线程2:

while(!inited ){

  sleep()

}

doSomethingwithconfig(context);

  The possible sentence 2 will be executed before the statement 1, so long may result in context has not been initialized, and the thread 2 on the use of uninitialized context to operate, cause an error.

  Here if the volatile keyword inited variable modified, it would not have this problem, because when the statement is executed to 2, will be able to ensure that context has been initialized.

3, can not guarantee atomicity

== not guarantee that any volatile operating variables are atomic ==, such as i ++.

Three, synchronized keyword

  synchronized: keywords, it depends on the JVM, to ensure the same time only one thread in the role of the object 's scope to operate within.

1, the memory Visibility:

  Visibility is determined by the sync block " before performing the unlock operation on a variable, this variable must be synchronized back to the first main memory (execution store, write operation) " obtained by this rule.

  In the Java memory model, synchronized provisions, thread when locked, first clear the working memory → in the main memory copy of a copy of the latest variable into the working memoryfinished executing code → change the value of the shared variable flushed to main memory in → release the mutex .

2, the atomic operations:

  Providing atomicity operation program mutex, only one thread at a time can be operated on a block code.

  • Modified synchronized code block , acting on the java volatile solve the problem of visibility.
  • synchronized modification of the method , the role of java in volatile solve the visibility problem.
  • synchronized modified static method , applied to all objects of this class
  • synchronized modified class , the role of this class of all objects

3, orderliness

  java with the synchronized keyword as one of the means to ensure the orderly execution of multi-threaded environment. When a piece of code will modify the shared variable, this piece of code to be mutually exclusive zones or critical regions , in order to ensure the correctness of the shared variable, synchronized marked a critical region.

synchronized(锁){

Critical section of code

}

  一个线程执行临界区代码过程如下: 
    1 获得同步锁 
    2 清空工作内存 
    3 从主存拷贝变量副本到工作内存 
    4 对这些变量计算 
    5 将变量从工作内存写回到主存 
    6 释放锁

  Visible, the synchronized both to ensure the multi-threaded concurrency orderliness , but also ensure the visibility of memory multithreading .

Fourth, the volatile and relatively Synchronized

1) Synchronized ensure atomicity and visibility of memory operations, Volatile memory can only be guaranteed visibility.

2) volatile does not require locking, and more lightweight than Synchronized, and will not block the thread (volatile will not cause obstruction thread; synchronized may cause obstruction thread).

3) volatile variables are not labeled optimizing compiler, and may be synchronized flag variable optimizing compiler (e.g., compiler optimization discouraged sort)

4) volatile modifier is variable, the variable can only be used, and a method or modifier is synchronized block

五、ReentrantLock

Fair and unfair lock locks two differences:

  • Unfair lock after a call to lock, it will first call the CAS to conduct a lock to grab, if this happens when the lock is not occupied, then get directly to the lock returned.

  • Unfair lock after CAS failed and fair as will lock into tryAcquire method, tryAcquire method, if it is found that the lock is released when the (state == 0), CAS unfair lock will directly grab the lock, but the lock fair waiting queue determines whether a thread is in a wait state, if the lock has not rob, baby discharged later.

Fair and unfair lock lock on these two differences, these two CAS if not successful, then the back of non-equity and equity-locking lock is the same, will enter the blocking queue waiting wake.

In contrast, non-fair locks have better performance because of its relatively large throughput. Of course, unfair to make time to acquire lock lock becomes more uncertain, it could lead to a thread in the blocking queue of chronically hungry.

1, ReentrantLock Introduction

ReentrantLock is JDK1.5 introduced, it has synchronized with the same concurrency and memory semantics, and provides other advanced features beyond synchonized of (for example, break a lock wait, condition variables, etc.), and use ReentrantLock get better than synchronized scalability.

ReentrantLock based implementation AQS (AbstractQueuedSynchronizer) and LockSupport .
AQS main primitive instruction using hardware ( CAS-Compare-and the swap ), to achieve a lightweight multi-thread synchronization mechanism, and does not cause the CPU to the above switching and scheduling, while providing visibility of memory and updating to ensure atomization (thread-safe the three elements: atoms, visibility, sequential).

Is a base frame synchronizer / lock essentially blocking the AQS, its main function is to provide a lock, the lock is released, and maintains a FIFO queue for storing the lock contention and blocking due to the internal threads.

2, the key code analysis

2.1. Key Field

AQS使用链表作为队列,使用volatile变量state,作为锁状态标识位。
    /**
     * Head of the wait queue, lazily initialized.  Except for
     * initialization, it is modified only via method setHead.  Note:
     * If head exists, its waitStatus is guaranteed not to be
     * CANCELLED.
     */
    private transient volatile Node head;//等待队列的头

    /**
     * Tail of the wait queue, lazily initialized.  Modified only via
     * method enq to add new wait node.
     */
    private transient volatile Node tail;//等待队列的尾

    /**
     * The synchronization state.
     */
    private volatile int state;//原子性的锁状态位,ReentrantLock对该字段的调用是通过原子操作compareAndSetState进行的

    /**
     * Atomically sets synchronization state to the given updated
     * value if the current state value equals the expected value.
     * This operation has memory semantics of a <tt>volatile</tt> read
     * and write.
     *
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that the actual
     *         value was not equal to the expected value.
     */
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

2.2.ReentrantLock fair locking and non-locking fair

Can be seen from the constructor ReentrantLock, ReentrantLock offers two locks: Lock fair and unfair lock its internal implemented two synchronizer NonfairSync, FairSync derived from AQS, mainly before using the template method pattern, the major rewrite of the AQS the tryAcquire, lock method, as shown below.

Here Insert Picture Description

    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

2.3 Get lock operation

 public void lock() {
        sync.lock();
 }

Because NonfairSync, FairSync were realized lock method, we will discuss separately:

NonfairSync.lock () analysis

(1) by comparing the atomic and set operation, if successfully set, indicating that the lock is free, the current thread to acquire the lock, and the current thread is set to lock owner;
(2) Otherwise, the call acquire method;

package java.util.concurrent.locks.ReentrantLock;
final void lock() {
            if (compareAndSetState(0, 1))//表示如果当前state=0,那么设置state=1,并返回true;否则返回false。由于未等待,所以线程不需加入到等待队列
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
}
 
 package java.util.concurrent.locks.AbstractOwnableSynchronizer  //AbstractOwnableSynchronizer是AQS的父类
 protected final void setExclusiveOwnerThread(Thread t) {
            exclusiveOwnerThread = t;
}

2) acquire Analysis Method

(1) If the exclusive manner tryAcquire attempt to acquire the lock fails, then put the current thread to a package Node, is added to the waiting queue; queued if successful, the node next checks whether the current thread should wait (suspend), If the wait state of the current thread prior to a node which node is less than 0, then the current thread suspended by LockSupport; regardless of whether the thread is suspended, pending or after activation, should return to the state of the current thread interrupt, if the interrupt is state, need to interrupt the current thread.

package java.util.concurrent.locks.AbstractQueuedSynchronizer
public final void acquire(int arg) {
         if (!tryAcquire(arg) &&
              acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
             selfInterrupt();
}

 
  protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
 }

3) nonfairTryAcquire Analysis
(1) == If the lock status is idle (state = 0), and by comparing the atomic operation and set, then the current thread to acquire the lock, and the current thread is the lock owner is set to ==;
(2) if lock status is idle, and relatively atoms and set the operation fails, then returns false, shows that attempts to obtain a lock failure;
(3) otherwise, check the current thread with the lock owner threads are equal (represents a thread already obtained the lock, requires that once again lock, this is called reentrant lock), if they are equal, the maintenance lock status, and return to true;
(4) if not above, showing that the lock has been held by another thread, direct return false;

final boolean nonfairTryAcquire(int acquires) {  
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {  //表示一个线程已经获得该锁,再次要求该锁(重入锁的由来),为状态位加acquires
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
 }

4) addWaiter analysis

(1) If the tail node is not null, described queue is not empty, put a new node is added to the rear of the tail, the current node returns, otherwise go enq process (2);

(2) If the tail node is null, described queue is empty, the need to establish a virtual head node, and the nodes encapsulated set for the current thread tail node; Further the occurrence of a situation is given in (1) compareAndSetTail failure may occur, where an infinite loop for the enq, is to ensure that the current thread to correctly enter the waiting queue;

addWaiter

package java.util.concurrent.locks.AbstractQueuedSynchronizer
   private Node addWaiter(Node mode) {
         Node node = new Node(Thread.currentThread(), mode);
         // Try the fast path of enq; backup to full enq on failure
         Node pred = tail;
         if (pred != null) {  //如果当前队列不是空队列,则把新节点加入到tail的后面,返回当前节点,否则进入enq进行处理。
              node.prev = pred;
              if (compareAndSetTail(pred, node)) {
                  pred.next = node;
                  return node;
              }
         }
         enq(node);
         return node;
     }

enq

package java.util.concurrent.locks.AbstractQueuedSynchronizer
 private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // tail节点为空,说明是空队列,初始化头节点,如果成功,返回头节点
                Node h = new Node(); // Dummy header
                h.next = node;
                node.prev = h;
                if (compareAndSetHead(h)) {
                    tail = node;
                    return h;
                }
            }
            else {   //
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }

5) acquireQueued analysis

(1) If the current node is the head of the queue node (if the first node is a virtual node, then the second node is actually the head node), you try to acquire this lock tryAcquire (arg). If successful it will be the first node to the current node (regardless of whether the first node is a virtual node), return interrupt status. Otherwise, (2) shouldParkAfterFailedAcquire.

(2) to detect whether the current node should park () - "Pending meaning," if it should park () to suspend the current thread and return the current thread interrupt status. Operation (1).

final boolean acquireQueued(final Node node, int arg) {
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } catch (RuntimeException ex) {
            cancelAcquire(node);
            throw ex;
        }
     } 

6) shouldParkAfterFailedAcquire分析

(1) If a node on standby before the waitStatus <0, which is in front of the node has not been to the lock, then returns true, indicates that the current node (thread) should park () a. Otherwise, (2).

(2) If a wait state before the node waitStatus> 0, i.e. before a node is CANCELLED, then the node will be removed before, recursively this until all the former node waitStatus <= 0, for (4). Otherwise, (3).

A node waits (3) a state before waitStatus = 0, a node status bit is modified before SINGAL, followed showing processing node waits for you, wait state based on its need to decide whether the park (). For (4).

(4) returns false, indicates that the thread should not park ().

Note: a node Node Status and modes may include the following:

        /** waitStatus value to indicate thread has cancelled */    取消
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */   信号等待(在AQS中,是通过LockSupport进行线程间信号交互的) 
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */       条件等待    
        static final int CONDITION = -2;
        /** Marker to indicate a node is waiting in shared mode */  共享模式
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */           独占模式
        static final Node EXCLUSIVE = null;
   /**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
    /**
     * Convenience method to park and then check if interrupted
     *
     * @return {@code true} if interrupted
     */
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
 private static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

FairSync.lock () analysis

== lock relatively fair and unfair lock, the lock on the acquisition achieved only difference in their tryAcquire FairSync () method to achieve == following code:

(1) if the lock state is 0, queue is empty, or a given head of the queue in the thread, then the thread obtains a lock;
(2) If the current thread is the lock owner equal to the thread, belonging to the lock case reentrant, plus a lock status requests;
(3) the above two cases are not, returns false, described failed attempts to acquire the lock;

protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (isFirst(current) &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }


    final boolean isFirst(Thread current) {
        Node h, s;
        return ((h = head) == null ||
                ((s = h.next) != null && s.thread == current) ||
                fullIsFirst(current)); //头为null,头的下个节点不是空且该节点的线程与当前线程是相等的,
    }

    final boolean fullIsFirst(Thread current) {
        // same idea as fullGetFirstQueuedThread
        Node h, s;
        Thread firstThread = null;//如果头不为空,且头的下个节点也不为空,且该节点的上一个节点是头节点,且该节点的线程不为null
        if (((h = head) != null && (s = h.next) != null &&
             s.prev == head && (firstThread = s.thread) != null))
            return firstThread == current;
        Node t = tail;
        while (t != null && t != head) {
            Thread tt = t.thread;
            if (tt != null)
                firstThread = tt;
            t = t.prev;
        }
        return firstThread == current || firstThread == null;
    }

Six, Synchronized contrast with ReentrantLock

1, reentrancy:

Understand from the name, ReenTrantLock literally means re-entering the lock, in fact, used the synchronized keyword lock is reentrant little difference between the two about this. == Both are entered every time the same thread, lock counters are incremented by one, so have to wait until the lock counter drops to zero to release the lock ==.

2, lock implementation

For == Synchronized ==, it is the keyword java language, is the native syntax level mutual exclusion is required == jvm == achieve. And == ReentrantLock == == API which is provided after the level of the JDK == 1.5 mutex required lock () and unlock () method with the try / finally statement block to complete

3, the performance difference:

Before Synchronized optimization, synchronized performance than ReenTrantLock much, but since the introduction of the biased locking == Synchronized, after lightweight lock (spin locks) ==, the performance difference between the two is almost in two ways case are available, official even suggested the use of synchronized, in fact, I feel synchronized optimization techniques borrowed CAS ReenTrantLock in. They are trying to put in user mode locking problem solve and avoid thread blocking into the kernel mode.

4, functional differences:

Convenience: Obviously == Synchronized relatively simple and convenient to use, and by the compiler to ensure the lock and lock release ==, and == ReenTrantLock need to manually declare to lock and release the lock, the lock is released by hand in order to avoid causing forget deadlock, so it is best to release the lock == statement in the finally.

Fine-grained locks and flexibility: Obviously ReenTrantLock better Synchronized

5, ReenTrantLock unique capabilities:

  1. == ReenTrantLock can specify whether fair or unfair lock lock. The only non-synchronized lock == fair. The so-called fair lock is the first thread is waiting to acquire the lock.
  2. == ReenTrantLock provides a Condition (condition) == class that implements thread are grouped need to wake up wake up, not like synchronized or random wake up wake up a thread or all threads.
  3. == == ReenTrantLock provides a mechanism capable of interrupting the thread waiting for the lock to implement this mechanism by lock.lockInterruptibly ().

Seven, CAS (Compare-and-Swap) compare and replace - processor instructions

1, CAS command

CAS instruction requires three operands, respectively == == memory location (in Java can be simply understood as a variable memory address is represented by V), the expected value of the old == == (indicated by A) and = == = new value (represented by B).

When the CAS instruction is executed, if and only if V in line with the expected old value A, the processor with the new value B V updated, otherwise it will not perform an update, but whether or not to update the value of V, will return the old value of V, the above-described process is an atomic operation.

2, Unsafe Deliverable

After jdk1.5, Java programs can use CAS operation that package provided by several methods sun.misc.Unsafe class inside compareAndSwapInt and compareAndSwapLong other virtual machines inside to do a special deal with these methods, time compilation the result is a processor out of the CAS command a platform-dependent, there is no process method call, or may be considered to be unconditionally linked into it.

  Because == Unsafe class is not available to the user class == procedure calls (Code Unsafe.getUnsafe () in the limit class loader (Bootstrap ClassLoader) to load only the start of the Class to access it ), so if you do not use reflection means we can only use it indirectly through other Java API.

2.1、AtomicInteger

2.1.1, unsafe examples

== == inside the bag as the java.util.concurrent integer atoms class == AtomicInteger ==, which of compareAndSet () and getAndIncrement () method and the like are used CAS Unsafe operation class.

 // setup to use Unsafe.compareAndSwapInt for updates

  //unsafe实例采用Unsafe类中静态方法getUnsafe()得到,但是这个方法如果我们写的时候调用会报错,
  //因为这个方法在调用时会判断类加载器,我们的代码是没有“受信任”的,而在jdk源码中调用是没有任何问题的

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    private static final long valueOffset;

 

    static {

      try {

        valueOffset = unsafe.objectFieldOffset

            (AtomicInteger.class.getDeclaredField("value"));

      } catch (Exception ex) { throw new Error(ex); }

    }

    private volatile int value;//volatile关键字保证了在多线程中value的值是可见的,任何一个线程修改了value值,会将其立即写回内存当中

2.1.2, getAndIncrement methods, effect of the method of operation corresponds to i ++

== getAndIncrement == function is:
i is compared with current, if i becomes equal values put next;
this time can guarantee int next = current + 1; and IF (); other threads will not be preempted between (because the value of i is not changed during this period), it will do if the spin operation is preempted. This may be achieved in a way atomicity operations.

This is an atomic operation is achieved without locking of programming a clever way, not only in the java jvm species, even in the underlying operating system to achieve concurrent application mechanism also has a large number of CAS.

    /**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

3, CAS shortcomings

ABA problem:

  For example, a thread is taken out from the memory location V A, this time another thread A 2 is also removed from memory, and some thread 2 into operation to B, then thread data V 2 in turn into position A this time thread 1 CAS operation is still found in memory A, then thread a successful operation. Despite the success of CAS thread 1 operations, but there may be problems lurking. As follows:

img

  A singly linked list with a conventional stack implementation, the stack is A, it has been known A.next time thread T1 is B, then the desired stack is replaced with CAS B:

  head.compareAndSet(A,B);

  Before performing the above T1 this instruction, thread T2 intervention, the A, B out of the stack, and then pushD, C, A, if the stack structure as shown below, while the object B is now in the free state:

      img

  At this time, the CAS operation performed turn thread T1 detected as being still stack A, the CAS successful, the stack becomes B, but in fact B.next is null, so in this case the situation becomes:

     img

  Wherein the stack list only one element B, C, and D is no longer present in the stack, no reason put C, D lost.

  From the beginning of the JDK atomic Java1.5 package provides a class == AtomicStampedReference to solve the problem == ABA. The method of action of this class == == == of compareAndSet first check is whether the current reference equal to the expected reference and the current mark is equal to the expected flag, if all equal Atomically and the reference value of the flag is set for a given the updated value ==.

    /**
     * Atomically sets the value of both the reference and stamp
     * to the given update values if the
     * current reference is {@code ==} to the expected reference
     * and the current stamp is equal to the expected stamp.
     *
     * @param expectedReference  预期引用值
     * @param newReference 更新后的引用
     * @param expectedStamp 预期标志
     * @param newStamp 更新后的标志
     * @return true if successful
     */
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }

  The actual application code:

private static AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<Integer>(100, 0);

.......................
atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);

Long cycle time overhead large:

  == spin CAS (unsuccessful, the cycle has been executed until success ==) if not successful for a long time, will bring a very large CPU execution cost . If the JVM can support pause instructions provided by the processor so there will be some efficiency improvement, pause command serves two purposes, first it may delay pipelined execution of instructions (de-pipeline), the CPU does not consume too many resources for implementation, delay time implementation dependent, the delay time on the number of processors is zero. It can avoid a second exit loop when the order due to memory conflicts (memory order violation) caused by CPU pipeline is cleared (CPU pipeline flush), in order to improve the efficiency of the CPU.

A shared variable can only guarantee atomic operations:

When performing operations on a shared variable, we can use the CAS cycle approach to ensure an atomic operation, but when == multiple shared variables operating cycle CAS can not guarantee atomic == operation.

  This time you can lock == == == or have a tricky way, is to merge multiple shared variables into a shared variable to the operation ==. For example there are two shared variables i = 2, j = a, merge at ij = 2a, and to operate with CAS ij. From the beginning Java1.5 == AtomicReference, JDK classes provided to guarantee the atomicity == references between objects, you can put == variable in a plurality of objects in the CAS operation is performed ==.

Guess you like

Origin www.cnblogs.com/amunamuna/p/11088374.html