Unsafe-CAS操作一个对象的status值

本文详细解释了如何在Java中利用CAS操作(CompareandSwap)和Unsafe类的偏移量来处理多线程并发控制,展示了在多线程环境下通过CAS操作安全地修改对象状态的过程,同时强调了底层操作的复杂性和推荐使用高级并发工具的必要性。
摘要由CSDN通过智能技术生成

如下代码主要展示了如何使用 CAS(Compare and Swap)操作来实现多线程并发控制。

在这个例子中,CAS 主要用于修改对象中的 statusname 字段。

在 Java 中,CAS 操作是通过 Unsafe 类来实现的,它可以直接操作对象的内存,而不受 Java 内存模型的限制。在这段代码中,通过 Unsafe 类获取了 statusname 字段在对象中的偏移量 statusOffsetnameOffSet,然后通过 CAS 操作来修改这些字段的值。

为什么要通过偏移量来进行 CAS 操作呢?这是因为 CAS 操作是基于对象内存地址进行的,而不是对象的引用或名称。通过偏移量,可以直接确定对象内部字段在内存中的位置,从而正确地执行 CAS 操作。

在这段代码中,通过获取 statusname 字段在对象中的偏移量,可以在多线程环境下安全地对这些字段进行修改,而不会出现数据竞争或错误修改的情况。

需要注意的是,直接操作对象内存是一种底层的编程技巧,需要谨慎使用,并且在高级应用中建议使用更高级的并发工具和模式来实现并发控制。


public class CASTest {

    private volatile int status;

    private static final Unsafe unsafe;

    // 对于 Java AbstractQueuedSynchronizer (AQS) 中的 stateOffset 字段,
    // 通常会使用 static final 修饰是因为这个偏移量值在整个类中都是不变的,且所有实例都需要使用相同的偏移量来进行 CAS 操作。
    // 即:不管有多少个 Bean 对象,对于Bean对象中的status操作的偏移量值是固定的,可以使用 static final
    // statusOffset 只是一个相对的偏移量,跟status具体的值无关,所以可以多实例共享statusOffset
    private static final long statusOffset;

    private volatile String name;

    private static final long nameOffSet;

    static {
        try {
            // sun.misc 中的class无法像AQS中那样通过 private static final Unsafe unsafe = Unsafe.getUnsafe(); 直接调用
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
            statusOffset = unsafe.objectFieldOffset(CASTest.class.getDeclaredField("status"));
            nameOffSet = unsafe.objectFieldOffset(CASTest.class.getDeclaredField("name"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        CASTest casTest = new CASTest();
        System.out.println("statusOffset:" + CASTest.statusOffset);
        System.out.println("status:" + casTest.status);
        System.out.println("name:" + casTest.name);
        System.out.println("nameOffSet:" + CASTest.nameOffSet);
        // 多线程并发cas操作status 0->1
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(() -> {
                boolean nameSetSuccess = unsafe.compareAndSwapObject(casTest, nameOffSet, null, "张三");
                if (nameSetSuccess) {
                    System.out.println(finalI + "==============-name:===============" + casTest.name);
                    System.out.println(finalI + "============-nameOffSet:================" + nameOffSet);
                } else {
                    System.out.println(finalI + "-name:" + casTest.name);
                    System.out.println(finalI + "-nameOffSet:" + nameOffSet);
                }
                boolean success = unsafe.compareAndSwapInt(casTest, statusOffset, 0, 1);
                if (success) {
                    System.out.println(finalI + "=============-statusOffset:===========" + statusOffset);
                    System.out.println(finalI + "=============-status:=============" + casTest.status);

                } else {
                    System.out.println(finalI + "-statusOffset:" + statusOffset);
                    System.out.println(finalI + "-status:" + casTest.status);
                }
            }).start();
        }
    }
}

这段代码主要展示了如何使用 CAS(Compare and Swap)操作来实现多线程并发控制,并通过偏移量来操作对象中的字段。下面是对代码的分析及流程讲解:

  1. 首先定义了一个 CASTest 类,其中包含了一个 volatile int status 和一个 volatile String name 字段,以及相应的静态变量 Unsafe unsafelong statusOffsetlong nameOffSet

  2. 在静态代码块中,通过反射的方式获取 Unsafe 对象,并获取了 statusname 字段在内存中的偏移量 statusOffsetnameOffSet

  3. main 方法中,创建了一个 CASTest 对象 casTest,并打印了 statusOffsetstatusnamenameOffSet 的值。

  4. 接着使用了一个循环创建了10个线程,每个线程内部执行了以下操作:

    • 使用 Unsafe.compareAndSwapObject 方法尝试将 name 字段由 null 修改为 "张三",并根据操作结果输出相关信息。
    • 使用 Unsafe.compareAndSwapInt 方法尝试将 status 字段由 0 修改为 1,并根据操作结果输出相关信息。
  5. 在多线程并发操作中,每个线程都尝试使用 CAS 操作来修改 namestatus 字段的值。由于 CAS 是一种乐观锁的机制,会比较对象当前值和期望值,如果一致则进行更新,否则不会更新并返回失败。

  6. 通过输出结果可以观察到多线程并发时对 namestatus 字段的操作情况,以及 CAS 操作的成功与失败情况。

总体来说,这段代码演示了如何使用 CAS 操作和偏移量来实现多线程并发控制,尤其是在底层操作对象内存时的一种实践。需要注意的是,对于普通业务开发而言,推荐使用更高级的并发工具和模式来确保数据安全性和可靠性。

结果展示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进窄门见微光行远路

如果对你有比较大的帮助

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值