Java concurrency之AtomicLongFieldUpdater原子类_动力节点Java学院整理
AtomicLongFieldUpdater介绍和函数列表
AtomicLongFieldUpdater可以对指定"类的'volatilelong'类型的成员"进行原子更新。它是基于反射原理实现的。
AtomicLongFieldUpdater函数列表
//受保护的无操作构造方法,供子类使用。 protectedAtomicLongFieldUpdater() //以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。 longaddAndGet(Tobj,longdelta) //如果当前值==预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。 abstractbooleancompareAndSet(Tobj,longexpect,longupdate) //以原子方式将此更新器管理的给定对象字段当前值减1。 longdecrementAndGet(Tobj) //获取此更新器管理的在给定对象的字段中保持的当前值。 abstractlongget(Tobj) //以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。 longgetAndAdd(Tobj,longdelta) //以原子方式将此更新器管理的给定对象字段当前值减1。 longgetAndDecrement(Tobj) //以原子方式将此更新器管理的给定对象字段的当前值加1。 longgetAndIncrement(Tobj) //将此更新器管理的给定对象的字段以原子方式设置为给定值,并返回旧值。 longgetAndSet(Tobj,longnewValue) //以原子方式将此更新器管理的给定对象字段当前值加1。 longincrementAndGet(Tobj) //最后将此更新器管理的给定对象的字段设置为给定更新值。 abstractvoidlazySet(Tobj,longnewValue) //为对象创建并返回一个具有给定字段的更新器。 staticAtomicLongFieldUpdaternewUpdater(Classtclass,StringfieldName) //将此更新器管理的给定对象的字段设置为给定更新值。 abstractvoidset(Tobj,longnewValue) //如果当前值==预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。 abstractbooleanweakCompareAndSet(Tobj,longexpect,longupdate)
AtomicLongFieldUpdater示例
//LongTest.java的源码 importjava.util.concurrent.atomic.AtomicLongFieldUpdater; publicclassLongFieldTest{ publicstaticvoidmain(String[]args){ //获取Person的class对象 Classcls=Person.class; //新建AtomicLongFieldUpdater对象,传递参数是“class对象”和“long类型在类中对应的名称” AtomicLongFieldUpdatermAtoLong=AtomicLongFieldUpdater.newUpdater(cls,"id"); Personperson=newPerson(12345678L); //比较person的"id"属性,如果id的值为12345678L,则设置为1000。 mAtoLong.compareAndSet(person,12345678L,1000); System.out.println("id="+person.getId()); } } classPerson{ volatilelongid; publicPerson(longid){ this.id=id; } publicvoidsetId(longid){ this.id=id; } publiclonggetId(){ returnid; } }
运行结果:
id=1000
AtomicLongFieldUpdater源码分析(基于JDK1.7.0_40)
AtomicLongFieldUpdater完整源码
/* *ORACLEPROPRIETARY/CONFIDENTIAL.Useissubjecttolicenseterms. * * * * * * * * * * * * * * * * * * * * */ /* * * * * * *WrittenbyDougLeawithassistancefrommembersofJCPJSR- *ExpertGroupandreleasedtothepublicdomain,asexplainedat *http://creativecommons.org/publicdomain/zero/./ */ packagejava.util.concurrent.atomic; importjava.lang.reflect.*; importsun.misc.Unsafe; importsun.reflect.CallerSensitive; importsun.reflect.Reflection; /** *Areflection-basedutilitythatenablesatomicupdatesto *designated{@codevolatile}referencefieldsofdesignated *classes.Thisclassisdesignedforuseinatomicdatastructures *inwhichseveralreferencefieldsofthesamenodeare *independentlysubjecttoatomicupdates.Forexample,atreenode *mightbedeclaredas * *{@code *classNode{ *privatevolatileNodeleft,right; * *privatestaticfinalAtomicReferenceFieldUpdater* *leftUpdater= *AtomicReferenceFieldUpdater.newUpdater(Node.class,Node.class,"left"); *privatestaticAtomicReferenceFieldUpdater rightUpdater= *AtomicReferenceFieldUpdater.newUpdater(Node.class,Node.class,"right"); * *NodegetLeft(){returnleft;} *booleancompareAndSetLeft(Nodeexpect,Nodeupdate){ *returnleftUpdater.compareAndSet(this,expect,update); *} *//...andsoon *}} Notethattheguaranteesofthe{@codecompareAndSet} *methodinthisclassareweakerthaninotheratomicclasses. *Becausethisclasscannotensurethatallusesofthefield *areappropriateforpurposesofatomicaccess,itcan *guaranteeatomicityonlywithrespecttootherinvocationsof *{@codecompareAndSet}and{@codeset}onthesameupdater. * *@since. *@authorDougLea *@param
Thetypeoftheobjectholdingtheupdatablefield *@param Thetypeofthefield */ publicabstractclassAtomicReferenceFieldUpdater { /** *Createsandreturnsanupdaterforobjectswiththegivenfield. *TheClassargumentsareneededtocheckthatreflectivetypesand *generictypesmatch. * *@paramtclasstheclassoftheobjectsholdingthefield. *@paramvclasstheclassofthefield *@paramfieldNamethenameofthefieldtobeupdated. *@returntheupdater *@throwsIllegalArgumentExceptionifthefieldisnotavolatilereferencetype. *@throwsRuntimeExceptionwithanestedreflection-based *exceptioniftheclassdoesnotholdfieldoristhewrongtype. */ @CallerSensitive publicstaticAtomicReferenceFieldUpdaternewUpdater(Classtclass,Class vclass,StringfieldName){ returnnewAtomicReferenceFieldUpdaterImpl(tclass, vclass, fieldName, Reflection.getCallerClass()); } /** *Protecteddo-nothingconstructorforusebysubclasses. */ protectedAtomicReferenceFieldUpdater(){ } /** *Atomicallysetsthefieldofthegivenobjectmanagedbythisupdater *tothegivenupdatedvalueifthecurrentvalue{@code==}the *expectedvalue.Thismethodisguaranteedtobeatomicwithrespectto *othercallsto{@codecompareAndSet}and{@codeset},butnot *necessarilywithrespecttootherchangesinthefield. * *@paramobjAnobjectwhosefieldtoconditionallyset *@paramexpecttheexpectedvalue *@paramupdatethenewvalue *@returntrueifsuccessful. */ publicabstractbooleancompareAndSet(Tobj,Vexpect,Vupdate); /** *Atomicallysetsthefieldofthegivenobjectmanagedbythisupdater *tothegivenupdatedvalueifthecurrentvalue{@code==}the *expectedvalue.Thismethodisguaranteedtobeatomicwithrespectto *othercallsto{@codecompareAndSet}and{@codeset},butnot *necessarilywithrespecttootherchangesinthefield. * * May
failspuriously *anddoesnotprovideorderingguarantees,soisonlyrarelyan *appropriatealternativeto{@codecompareAndSet}. * *@paramobjAnobjectwhosefieldtoconditionallyset *@paramexpecttheexpectedvalue *@paramupdatethenewvalue *@returntrueifsuccessful. */ publicabstractbooleanweakCompareAndSet(Tobj,Vexpect,Vupdate); /** *Setsthefieldofthegivenobjectmanagedbythisupdatertothe *givenupdatedvalue.Thisoperationisguaranteedtoactasavolatile *storewithrespecttosubsequentinvocationsof{@codecompareAndSet}. * *@paramobjAnobjectwhosefieldtoset *@paramnewValuethenewvalue */ publicabstractvoidset(Tobj,VnewValue); /** *Eventuallysetsthefieldofthegivenobjectmanagedbythis *updatertothegivenupdatedvalue. * *@paramobjAnobjectwhosefieldtoset *@paramnewValuethenewvalue *@since1.6 */ publicabstractvoidlazySet(Tobj,VnewValue); /** *Getsthecurrentvalueheldinthefieldofthegivenobjectmanaged *bythisupdater. * *@paramobjAnobjectwhosefieldtoget *@returnthecurrentvalue */ publicabstractVget(Tobj); /** *Atomicallysetsthefieldofthegivenobjectmanagedbythisupdater *tothegivenvalueandreturnstheoldvalue. * *@paramobjAnobjectwhosefieldtogetandset *@paramnewValuethenewvalue *@returnthepreviousvalue */ publicVgetAndSet(Tobj,VnewValue){ for(;;){ Vcurrent=get(obj); if(compareAndSet(obj,current,newValue)) returncurrent; } } privatestaticfinalclassAtomicReferenceFieldUpdaterImpl extendsAtomicReferenceFieldUpdater { privatestaticfinalUnsafeunsafe=Unsafe.getUnsafe(); privatefinallongoffset; privatefinalClass tclass; privatefinalClass vclass; privatefinalClasscclass; /* *Internaltypecheckswithinallupdatemethodscontain *internalinlinedoptimizationscheckingforthecommon *caseswheretheclassisfinal(inwhichcaseasimple *getClasscomparisonsuffices)orisoftypeObject(in *whichcasenocheckisneededbecauseallobjectsare *instancesofObject).TheObjectcaseishandledsimplyby *settingvclasstonullinconstructor.ThetargetCheckand *updateCheckmethodsareinvokedwhenthesefaster *screeningsfail. */ AtomicReferenceFieldUpdaterImpl(Class tclass, Class vclass, StringfieldName, Class>caller){ Fieldfield=null; ClassfieldClass=null; intmodifiers=0; try{ field=tclass.getDeclaredField(fieldName); modifiers=field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller,tclass,null,modifiers); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); fieldClass=field.getType(); }catch(Exceptionex){ thrownewRuntimeException(ex); } if(vclass!=fieldClass) thrownewClassCastException(); if(!Modifier.isVolatile(modifiers)) thrownewIllegalArgumentException("Mustbevolatiletype"); this.cclass=(Modifier.isProtected(modifiers)&& caller!=tclass)?caller:null; this.tclass=tclass; if(vclass==Object.class) this.vclass=null; else this.vclass=vclass; offset=unsafe.objectFieldOffset(field); } voidtargetCheck(Tobj){ if(!tclass.isInstance(obj)) thrownewClassCastException(); if(cclass!=null) ensureProtectedAccess(obj); } voidupdateCheck(Tobj,Vupdate){ if(!tclass.isInstance(obj)|| (update!=null&&vclass!=null&&!vclass.isInstance(update))) thrownewClassCastException(); if(cclass!=null) ensureProtectedAccess(obj); } publicbooleancompareAndSet(Tobj,Vexpect,Vupdate){ if(obj==null||obj.getClass()!=tclass||cclass!=null|| (update!=null&&vclass!=null&& vclass!=update.getClass())) updateCheck(obj,update); returnunsafe.compareAndSwapObject(obj,offset,expect,update); } publicbooleanweakCompareAndSet(Tobj,Vexpect,Vupdate){ //sameimplementationasstrongformfornow if(obj==null||obj.getClass()!=tclass||cclass!=null|| (update!=null&&vclass!=null&& vclass!=update.getClass())) updateCheck(obj,update); returnunsafe.compareAndSwapObject(obj,offset,expect,update); } publicvoidset(Tobj,VnewValue){ if(obj==null||obj.getClass()!=tclass||cclass!=null|| (newValue!=null&&vclass!=null&& vclass!=newValue.getClass())) updateCheck(obj,newValue); unsafe.putObjectVolatile(obj,offset,newValue); } publicvoidlazySet(Tobj,VnewValue){ if(obj==null||obj.getClass()!=tclass||cclass!=null|| (newValue!=null&&vclass!=null&& vclass!=newValue.getClass())) updateCheck(obj,newValue); unsafe.putOrderedObject(obj,offset,newValue); } publicVget(Tobj){ if(obj==null||obj.getClass()!=tclass||cclass!=null) targetCheck(obj); return(V)unsafe.getObjectVolatile(obj,offset); } privatevoidensureProtectedAccess(Tobj){ if(cclass.isInstance(obj)){ return; } thrownewRuntimeException( newIllegalAccessException("Class"+ cclass.getName()+ "cannotaccessaprotectedmemberofclass"+ tclass.getName()+ "usinganinstanceof"+ obj.getClass().getName() ) ); } } }
下面分析LongFieldTest.java的流程。
1.newUpdater()
newUpdater()的源码如下:
publicstaticAtomicLongFieldUpdaternewUpdater(Classtclass,StringfieldName){ Class>caller=Reflection.getCallerClass(); if(AtomicLong.VM_SUPPORTS_LONG_CAS) returnnewCASUpdater(tclass,fieldName,caller); else returnnewLockedUpdater(tclass,fieldName,caller); }
说明:newUpdater()的作用是获取一个AtomicIntegerFieldUpdater类型的对象。
它实际上返回的是CASUpdater对象,或者LockedUpdater对象;具体返回哪一个类取决于JVM是否支持long类型的CAS函数。CASUpdater和LockedUpdater都是AtomicIntegerFieldUpdater的子类,它们的实现类似。下面以CASUpdater来进行说明。
CASUpdater类的源码如下:
publicbooleancompareAndSet(Tobj,longexpect,longupdate){ if(obj==null||obj.getClass()!=tclass||cclass!=null)fullCheck(obj); returnunsafe.compareAndSwapLong(obj,offset,expect,update); }
说明:它实际上是通过CAS函数操作。如果类的long对象的值是expect,则设置它的值为update。