AtomicInteger
 
 
getAndSet:设置为新值,返回设置之前的值。此方法为原子性操作,即保证在得到当前值与设置新值之间,没有任何其他更新操作。
 public final int getAndSet(int newValue) {
         for (;;) {
             int current = get();
             if (compareAndSet(current, newValue))
                 return current;
         }
     }
getAndIncrement:当前值加一,返回自增前的值。此方法为原子性操作,即保证在得到当前值与自增之间,没有任何其他更新操作。举个例子,假如是value++,两个线程同时调用此函数,两个线程都取到了当前值100,然后都基于100加一,最后得到101,miss掉了一次自增。采用compareAndSet,两个线程同时取到当前值100,线程一成功调用compareAndSet,当前值变为101,返回;线程二调用compareAndSet失败,回到循环头,重新取得一个新的当前值101,接着成功调用comareAndSet,更新当前值为102,返回
 
 public final int getAndIncrement() {
         for (;;) {
             int current = get();
             int next = current + 1;
            if (compareAndSet(current, next))
                 return current;
         }
 }compareAndSet:如果当前值与期望值(第一个参数)相等,则设置为新值(第二个参数),设置成功返回true。
public final boolean compareAndSet(int expect, int update) {
      return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
     }
Unsafe
ObjectFieldOffset:前文中出现的参数valueOffset是一个静态变量,调用Unsafe.objectFieldOffset得到
 
private static final long valueOffset;
 
static {
       try {
         valueOffset = unsafe.objectFieldOffset
             (AtomicInteger.class.getDeclaredField("value"));
       } catch(Exception   ex) { throw new Error  (ex); }
     }

compareAndSet:如果当前值与期望值相等,更新对象的一个整数属性(field)为给定的值。更新则返回true,否则为false。此方法为原子性操作,而且是native方法。
  public native boolean compareAndSwapInt(Object obj, long offset,
                                          int expect, int update);UnSafe native
在Java5 Concurrent包中的锁机制中,UnSafe的native代码从Kaffe(java 虚拟机的首个开源实现)中扒了出来。
首先得到属性(field)的指针,然后调用g_atomic_int_compare_and_exchange方法。
 
/**
 * Helper macro, defining a sun.misc.Unsafe compare and swap function 
 * with a given NAME tail and TYPE of arguments.
 */
#define KAFFE_UNSAFE_COMPARE_AND_SWAP(NAME, TYPE)
JNIEXPORT jboolean JNICALL Java_sun_misc_Unsafe_compareAndSwap ## NAME(JNIEnv* env, jobject unsafe UNUSED, jobject obj, jlong offset, TYPE expect, TYPE update) 
{ 
  volatile TYPE * address = getFieldAddress(env, obj, offset); 
  if (sizeof(TYPE) == sizeof(gint)) 
    return g_atomic_int_compare_and_exchange((volatile gint *) address, (gint) expect, (gint) update); 
  else if (sizeof(TYPE) == sizeof(gpointer)) 
    return g_atomic_pointer_compare_and_exchange((volatile gpointer *) address, (gpointer) expect, (gpointer) update); 
  else 
    if (*address == expect) { 
      *address = update; 
      return JNI_TRUE; 
    } 
    else 
      return JNI_FALSE; 
} GLIB
g_atomic_pointer_compare_and_exchange是glib中的一段c代码
gboolean g_atomic_int_compare_and_exchange (volatile gint *atomic, 
				   gint           oldval, 
				   gint           newval)
{
  gint result;
 
  __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
			: "=a" (result), "=m" (*atomic)
			: "r" (newval), "m" (*atomic), "0" (oldval) : ); 
  return result == oldval;
}GCC 内联汇编
汇编指令cmpxchg:上面的函数中嵌入了汇编语句(c代码中嵌入汇编,称为内联汇编),调用了一条汇编指令cmpxchgl(AT&T风格),对应Intel格式的汇编指令为cmpxchg。
根据古月今人的解释:cmpxchg是将寄存器(AL, AX或者EAX,取决于值的大小)中的值和目标操作数(第一个参数)进行比较,如果相等,则将源操作数(第二个参数)拷贝到目标操作数中,同时ZF置1;否则ZF置0,将目标操作数拷贝到EAX。
 
仿照百度blog的一篇文章,给出伪码为
%eax = old;
if (*address == %eax) {
   *address = new;
   zf = 1;
   return %eax;
} else {
   zf = 0;
   return *address;
}
内联汇编
GCC扩展内联汇编语法格式为:  asm ( assembler template 
           : output operands                  /* optional */
           : input operands                   /* optional */
           : list of clobbered registers      /* optional */
           );前文中"lock; cmpxchgl %2, %1"是汇编模板,指定汇编指令为cmpxchgl(AT&T格式),%2为源操作数,%1为目标操作数。
 “=a"(result), "=m"(*atomic) 是输出参数。
 "r"(newval), "m"(*atomic), "0"(oldval)是输入参数。参数前面的双引号内容表示对参数的限制,
- "r"是将参数放入寄存器中
- "="表示write-only,之前的值直接被替换为新值
- "a"表示eax寄存器
- "m"表示直接操作内存,而不是通过寄存器
- "0“表示使用和内联汇编中第一个操作数相同的寄存器,这里是和result使用相同的寄存器(eax)
- 将oldval送到eax寄存器中
- 调用汇编指令cmpxchgl,newval和*atomic作为其源操作数和目标操作数
- 将汇编指令调用的结果(在寄存器eax中)返回给result。*atomic有可能被更新。
加上LOCK前缀,保证原子性;否则要将类似前文java中,循环重试直到更新成功。
Volatile则避免编译器优化,打乱顺序(reorder)。
 
总结
 
java中的CAS调用底层的CAS操作。
AtomicInteger -> Unsafe -> Unsafe c 代码 -> 内联汇编 -> 汇编
参考
unsafe的源码: http://classpath.sourcearchive.com/documentation/0.97.1/Unsafe_8java-source.html
compare and exchange c实现: http://flow.yellowcouch.org/active/doxygen/cmpxchg_8h_source.html
X86汇编参考: http://www.cs.virginia.edu/~evans/cs216/guides/x86.html
 
 
                   
                   
                   
                   
                             本文详细探讨了Java并发包中的AtomicInteger类,重点解析了getAndSet、getAndIncrement和compareAndSet方法背后的CAS操作原理,以及如何通过Unsafe类实现原子性的更新操作。同时介绍了底层实现细节,包括内联汇编、GCC和GLIB中的原子交换算法,以及x86架构下原子操作的实现方式。
本文详细探讨了Java并发包中的AtomicInteger类,重点解析了getAndSet、getAndIncrement和compareAndSet方法背后的CAS操作原理,以及如何通过Unsafe类实现原子性的更新操作。同时介绍了底层实现细节,包括内联汇编、GCC和GLIB中的原子交换算法,以及x86架构下原子操作的实现方式。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
                     
              
             
                   284
					284
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
					 
					 
					


 
            