Java, CAS-ABA solutions to problems

Xinzhou SEO Summary

That exchange CAS contrast, it is the premise of ensuring atomicity of data as to reduce the use of the lock, using a large number of CAS are many programming language or system implementation.

 

了解CAS(Compare-And-Swap)

That exchange CAS contrast, it is the premise of ensuring atomicity of data as to reduce the use of the lock, using a large number of CAS are many programming language or system implementation.

CAS implementation in JAVA

JAVA in the cas mainly used Unsafe methods, Unsafe operation of CAS is mainly based on assembly instruction hardware platform, the current processor basic support CAS, but the realization of different manufacturers are not the same as nothing.

Unsafe CAS provides three methods for operating, respectively,

1
<p style= "line-height: 1.5em;" > public  final  native  boolean  compareAndSwapObject(Object value,  long  valueOffset, Object expect, Object update);<br> public  final  native  boolean  compareAndSwapInt(Object value,  long  valueOffset,  int  expect,  int  update);<br> public  final  native  boolean  compareAndSwapLong(Object value,  long  valueOffset,  long  expect,  long  update);<br></p>
  • value represents the object to be operated

  • valueOffset represents objects (value) of the offset address (through Unsafe.objectFieldOffset(Field valueField)acquisition)

  • When expect to update the expected value represents the value of

  • update represents the value that will be updated

The specific process for each operation in the implementation of CAS, the thread will do to get the current value of the contrast value of valueOffset to talk to expect if the same memory according to the changes and return true, if there are other threads are inconsistent instructions to modify the value of this object , false is returned

Unsafe class embodied compareAndSwapInt of:

1
<p style= "line-height: 1.5em;" >UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))<br>  UnsafeWrapper( "Unsafe_CompareAndSwapInt" );<br>  oop p = JNIHandles::resolve(obj);<br>  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);   return  (jint)(Atomic::cmpxchg(x, addr, e)) == e;<br>UNSAFE_END<br></p>

ABA problem

Thread 1 ready to modify the value of the A variables CAS, prior to this, other threads value of the variable is replaced by B of A, and replaced A consists of B, then find the value of the variable remains at A executing CAS threads 1, so the CAS success . But in fact this time the site has a different and original.

 

aba.png

example

1
<p style= "line-height: 1.5em;" > public  static  AtomicInteger a =  new  AtomicInteger( 1 ); public  static  void  main(String[] args){<br>    Thread main =  new  Thread(() -> {<br>        System.out.println( "操作线程"  + Thread.currentThread() + ",初始值 = "  + a);   //定义变量 a = 1<br>        try {<br>            Thread.sleep(1000);  //等待1秒 ,以便让干扰线程执行<br>        } catch (InterruptedException e) {<br>            e.printStackTrace();<br>        }        boolean isCASSuccess = a.compareAndSet(1,2); // CAS操作<br>        System.out.println("操作线程" + Thread.currentThread() +",CAS操作结果: " + isCASSuccess);<br>    },"主操作线程");<br><br>    Thread other = new Thread(() -> {<br>        Thread.yield();  //确保thread-main线程优先执行<br>        a.incrementAndGet(); // a 加 1, a + 1 = 1 + 1 = 2<br>        System.out.println("操作线程" + Thread.currentThread() +",【increment】 ,值 = "+ a);<br>        a.decrementAndGet(); // a 减 1, a - 1 = 2 - 1 = 1<br>        System.out.println("操作线程" + Thread.currentThread() +",【decrement】 ,值 = "+ a);<br>    },"干扰线程");<br><br>    main.start();<br>    other.start();<br>}<br></p>

Output> operation thread Thread [main operating thread, 5, main], initial value = 1>
operation thread Thread [interfering threads, 5, main], [increment], value = 2>
operation thread Thread [interfering threads, 5, main ], [] decrement value = 1>
operation thread thread [main operating thread, 5, main], CAS result: true

Solve the ABA program

Thinking

ABA solve the simplest solution is to add value to a modified version number every time the value changes, it will modify the version number are comparing this version number CAS operations.

aba_2.png

JAVA in the ABA solution (AtomicStampedReference)

AtomicStampedReference major maintenance and contains a reference to an object can be updated automatically integer "stamp" the pair ABA objects to solve the problem.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//关键代码
public  class  AtomicStampedReference<V> {
     private  static  class  Pair<T> {
         final  T reference;   //维护对象引用
         final  int  stamp;   //用于标志版本
         private  Pair(T reference,  int  stamp) {
             this .reference = reference;
             this .stamp = stamp;
         }
         static  <T> Pair<T> of(T reference,  int  stamp) {
             return  new  Pair<T>(reference, stamp);
         }
     }
     private  volatile  Pair<V> pair;
     ....
     /**
       * expectedReference :更新之前的原始值
       * newReference : 将要更新的新值
       * expectedStamp : 期待更新的标志版本
       * newStamp : 将要更新的标志版本
       */
     public  boolean  compareAndSet(V   expectedReference,
                                  V   newReference,
                                  int  expectedStamp,
                                  int  newStamp) {
         Pair<V> current = pair;  //获取当前pair
         return
             expectedReference == current.reference &&  //原始值等于当前pair的值引用,说明值未变化
             expectedStamp == current.stamp &&  // 原始标记版本等于当前pair的标记版本,说明标记未变化
             ((newReference == current.reference &&
               newStamp == current.stamp) ||  // 将要更新的值和标记都没有变化
              casPair(current, Pair.of(newReference, newStamp)));  // cas 更新pair
     }
}

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private  static  AtomicStampedReference<Integer> atomicStampedRef =
         new  AtomicStampedReference<>( 1 0 );
public  static  void  main(String[] args){
     Thread main =  new  Thread(() -> {
         System.out.println( "操作线程"  + Thread.currentThread() + ",初始值 a = "  + atomicStampedRef.getReference());
         int  stamp = atomicStampedRef.getStamp();  //获取当前标识别
         try  {
             Thread.sleep( 1000 );  //等待1秒 ,以便让干扰线程执行
         catch  (InterruptedException e) {
             e.printStackTrace();
         }
         boolean  isCASSuccess = atomicStampedRef.compareAndSet( 1 , 2 ,stamp,stamp + 1 );   //此时expectedReference未发生改变,但是stamp已经被修改了,所以CAS失败
         System.out.println( "操作线程"  + Thread.currentThread() + ",CAS操作结果: "  + isCASSuccess);
     }, "主操作线程" );
     Thread other =  new  Thread(() -> {
         Thread.yield();  // 确保thread-main 优先执行
atomicStampedRef.compareAndSet( 1 , 2 ,atomicStampedRef.getStamp(),atomicStampedRef.getStamp() + 1 );
         System.out.println( "操作线程"  + Thread.currentThread() + ",【increment】 ,值 = " + atomicStampedRef.getReference());
         atomicStampedRef.compareAndSet( 2 , 1 ,atomicStampedRef.getStamp(),atomicStampedRef.getStamp() + 1 );
         System.out.println( "操作线程"  + Thread.currentThread() + ",【decrement】 ,值 = " + atomicStampedRef.getReference());
     }, "干扰线程" );
     main.start();
     other.start();
}

 

// output

> 操作线程Thread[主操作线程,5,main],初始值 a = 2

> 操作线程Thread[干扰线程,5,main],【increment】 ,值 = 2

> 操作线程Thread[干扰线程,5,main],【decrement】 ,值 = 1

> 操作线程Thread[主操作线程,5,main],CAS操作结果: false

来源:内蒙古SEO

Guess you like

Origin www.cnblogs.com/1994jinnan/p/11985687.html