Unsafe 和 Atomic 详解(下)

简介: 在JDK 5之后,Java类库中才开始使用CAS操作,该操作由sun.misc.Unsafe类里面的 compareAndSwapInt()和compareAndSwapLong()等几个方法包装提供。HotSpot虚拟机在内部对这些方法做了特殊处理,即时编译出来的结果就是一条平台相关的处理器CAS指令,没有方法调用的过程, 或者可以认为是无条件内联进去了。

对象属性进行原子操作


  1. 获取属性偏移量


  1. 通过 CAS  方式进行修改


public class UnsafeTest {
    public static Unsafe U;
    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            U = (Unsafe)f.get(null);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        User user = new User();
        // 获取字段
        Field age = user.getClass().getDeclaredField("age");
        // 获取字段相对Java对象的"起始地址"的偏移量
        long offset = U.objectFieldOffset(age);
        // 设置值
        boolean success = U.compareAndSwapInt(user, offset, 10, 20) ;
        System.out.println("修改结果: " + success ) ;
        // 打印数据
        System.out.println("查询结果: " + user.getAge());
    }
}
class User {
    private int age;
    public User() {
        this.age = 10;
    }
    public int getAge() {
        return age;
    }
}
//输出结果
修改结果: true
查询结果: 20


注意事项


ABA 问题


ABA 是在 CAS 场景下面容易出现的问题,当一个数据的值为 A1, 然后再被修改为 B  ,最后再修改为 A2。 并且 A1 和 A2 相等;但是另外一个线程查询到的结果是 A1 , 此时更新为 C ,也可以成功。这样的风险就是后者不清楚数据是否被改变,并且能够成功修改。


举个例子:你钱包里面有 100 块钱,然后小偷偷走后又给你换回来了,你看到的还是钱包里面的 100 块钱吗?再比如你老婆和其他的男人出轨了,然后再还回来,你看到的还是你的老婆吗?其实这些问题已经触犯到道德和FL的范围。


针对 ABA 问题,我们可以通过 AtomicStampedReference 解决。


AtomicStampedReference


AtomicStampedReference 维护一个对象引用以及一个整数“stamp”,该整数可以进行原子更新。 实现说明:此实现通过创建表示“装箱”[reference,integer] 对的内部对象来维护戳记引用。在此之前我们先对 ABA 问题进行一个模拟:


public class ABATest {
    private static AtomicInteger index = new AtomicInteger(10);
    public static void main(String[] args) {
        new Thread(()-> {
            index.compareAndSet(10, 101);
            index.compareAndSet(101, 10);
            System.out.println(Thread.currentThread() + ": 10->101->10");
        }, "Tom").start();
        new Thread(()-> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean result = index.compareAndSet(10, 1000);
            System.out.println(Thread.currentThread() + ": 更新结果:" + result + ", 更新后的值: " + index.get());
        }, "Jack").start();
    }
}


通过 AtomicStampedReference 来解决这个问题:就是我们在进入第二个线程之前,先读取当前的版本号,然后进入更新。这个读取的版本号可能是一个旧的值。如果出现这种情况,那么我们执行 compareAndSet 就会返回失败。


public class ABATest2 {
    private static AtomicStampedReference index = new AtomicStampedReference(10, 1);
    public static void main(String[] args) {
        new Thread(() -> {
            index.compareAndSet(10, 101, index.getStamp(), index.getStamp() + 1);
            index.compareAndSet(101, 10, index.getStamp(), index.getStamp() + 1);
            System.out.println(Thread.currentThread() + ": 10->101->10");
        }, "Tom").start();
        int stamp = index.getStamp();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean result = index.compareAndSet(10, 1000, stamp, stamp + 1);
            System.out.println(Thread.currentThread() + ": 更新结果:" + result + ", 更新后的值: " + index.getReference());
        }, "Jack").start();
    }
}


返回结果如下所示:


Thread[Tom,5,main]: 10->101->10
Thread[Jack,5,main]: 更新结果:false, 更新后的值: 10


参考文档






相关文章
|
缓存 调度
Atomic 类
Atomic 类
65 0
|
5月前
|
安全 前端开发 Java
并发编程之原子操作Atomic&Unsafe
并发编程之原子操作Atomic&Unsafe
|
2月前
|
存储 安全 C++
C++ 原子变量atomic variable
原子变量是 C++11 引入的一种同步机制,用于多线程环境中的无锁、线程安全操作。其操作不可分割,避免了数据竞争和不一致问题。原子变量位于 `<atomic>` 头文件中,支持多种类型如 `std::atomic<T>` 和特化类型。基本用法包括定义原子变量、加载、存储、交换及比较交换操作。内存顺序(如 `std::memory_order_seq_cst`)用于控制内存访问顺序和可见性,适用于不同场景。原子变量常用于线程安全的计数器和标志位等。
|
6月前
|
安全 Java vr&ar
Atomic原子类总结
Atomic原子类总结
|
6月前
|
安全 C++
C++标准库中的锁lock_guard、unique_lock、shared_lock、scoped_lock、recursive_mutex
C++标准库中的锁lock_guard、unique_lock、shared_lock、scoped_lock、recursive_mutex
198 0
|
Java API
【Unsafe】
【Unsafe】
并发编程(八)Unsafe&Atomic
并发编程(八)Unsafe&Atomic
82 0
|
Java
CAS之什么是unsafe类(三)
CAS之什么是unsafe类(三)
208 0
CAS之什么是unsafe类(三)