- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicReferenceFieldUpdater
AtomicLongFieldUpdater和AtomicReferenceFieldUpdater
在AtomicLongFieldUpdater类中,由于有些32位系统一次性无法对64位的long进行原子运算,所以为了保证安全,在这些不能一次性进行原子运算的需要区分考虑,利用加synchronized锁来实现:
@CallerSensitive
public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
Class<?> caller = Reflection.getCallerClass();
if (AtomicLong.VM_SUPPORTS_LONG_CAS)
//直接cas实现
return new CASUpdater<U>(tclass, fieldName, caller);
else
//带synchronized锁实现
return new LockedUpdater<U>(tclass, fieldName, caller);
}
什么意思呢?下面给出几个具体方法:
直接CAS实现:
//直接CAS实现
public final boolean compareAndSet(T obj, long expect, long update) {
accessCheck(obj);
return U.compareAndSwapLong(obj, offset, expect, update);
}
加锁的CAS实现:
//加锁的CAS实现
public final boolean compareAndSet(T obj, long expect, long update) {
accessCheck(obj);
synchronized (this) {
long v = U.getLong(obj, offset);
if (v != expect)
return false;
U.putLong(obj, offset, update);
return true;
}
}
在其他方面, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater实现思想基本一致。
代码例子
:
// LongTest.java的源码
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class LongFieldTest {
public static void main(String[] args) {
// 获取Person的class对象
Class cls = Person.class;
// 新建AtomicLongFieldUpdater对象,传递参数是“class对象”和“long类型在类中对应的名称”
AtomicLongFieldUpdater mAtoLong = AtomicLongFieldUpdater.newUpdater(cls, "id");
Person person = new Person(12345678L);
// 比较person的"id"属性,如果id的值为12345678L,则设置为1000。
mAtoLong.compareAndSet(person, 12345678L, 1000);
System.out.println("id="+person.getId());
}
}
class Person {
volatile long id;
public Person(long id) {
this.id = id;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
}
@CallerSensitive
来看下这个注解是干啥的?
@CallerSensitive注解:
jdk内有些方法,jvm的开发者认为这些方法危险(一般是sun包下的类),不希望开发者调用,就把这种危险的方法用 @CallerSensitive修饰,并在“jvm”级别检查。(见:http://openjdk.java.net/jeps/176)
如Reflection.getCallerClass()方法规定,调用它的对象,必须有 @CallerSensitive 注解,否则 报异常 Exception in thread "main" java.lang.InternalError: CallerSensitive annotation expected at frame 1
@CallerSensitive还有个特殊之处,必须由 启动类classloader加载(如rt.jar ),才可以被识别。 所以rt.jar下面的注解可以正常使用。 开发者自己写的@CallerSensitive 不可以被识别。 但是,可以利用jvm参数 -Xbootclasspath/a: path 假装自己的程序是启动类。
-Xbootclasspath介绍:
-Xbootclasspath:bootclasspath :让jvm从指定的路径中加载bootclass,用来替换jdk的rt.jar。一般不会用到。
-Xbootclasspath/a: path : 被指定的文件追加到默认的bootstrap路径中。
-Xbootclasspath/p: path : 让jvm优先于默认的bootstrap去加载path中指定的class。
网友评论