美文网首页JUC 并发专题
原子字段更新器

原子字段更新器

作者: 程序员札记 | 来源:发表于2022-02-25 09:13 被阅读0次
  • 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。

相关文章

网友评论

    本文标题:原子字段更新器

    本文链接:https://www.haomeiwen.com/subject/rihxrrtx.html