如何在多线程环境下判断AtomicIntegerArray是否已经初始化?

林欢喜 Java经验 发布时间:2025-12-25 16:50:48 阅读数:15825 1
下文笔者讲述多线程环境下判断AtomicIntegerArray是否初始化的方法及示例分享,如下所示

多线程判断方法

多线程上判断,我们可采用以下步骤处理
      1. 第一次非空检查:无锁快速判断,
          绝大多数情况下直接返回已初始化对象,避免进入同步代码块;
      2. 同步锁:保证只有一个线程进入初始化逻辑,
          避免重复创建;
      3. 第二次非空检查:防止多个线程等待锁后,
           再次重复初始化;
     4. `volatile` 修饰引用:保证引用的可见性,
           禁止指令重排,避免其他线程获取到半初始化的对象。      
import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerArrayDCLInit {
    // 关键:用volatile修饰AtomicIntegerArray引用,保证可见性和禁止指令重排
    private static volatile AtomicIntegerArray atomicArray;

    /
      多线程安全的判断与获取方法
     /
    public static AtomicIntegerArray getAtomicArray() {
        // 第一次检查:无锁快速判断,避免不必要的锁竞争
        if (atomicArray == null) {
            // 同步锁:保证只有一个线程进入初始化流程
            synchronized (AtomicIntegerArrayDCLInit.class) {
                // 第二次检查:防止等待锁的线程重复初始化
                if (atomicArray == null) {
                    System.out.println(Thread.currentThread().getName() + ":开始初始化AtomicIntegerArray");
                    // 初始化原子数组(此处可根据业务需求指定长度或传入初始数组)
                    atomicArray = new AtomicIntegerArray(10);
                    System.out.println(Thread.currentThread().getName() + ":AtomicIntegerArray初始化完成");
                }
            }
        }
        // 若已初始化,直接返回;若未初始化,执行完上面的逻辑后返回
        return atomicArray;
    }

    /
      多线程环境下的测试方法
     /
    public static void main(String[] args) throws InterruptedException {
        // 启动20个线程,并发判断并获取AtomicIntegerArray
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                AtomicIntegerArray array = getAtomicArray();
                System.out.println(Thread.currentThread().getName() + ":获取到原子数组,长度:" + array.length());
            }, "工作线程-" + i).start();
        }

        // 等待所有线程执行完毕
        Thread.sleep(2000);
        System.out.println("所有线程执行完成,原子数组最终状态:" + (atomicArray != null ? "已初始化" : "未初始化"));
    }
}

运行结果(线程安全,仅一次初始化)

工作线程-0:开始初始化AtomicIntegerArray
工作线程-0:AtomicIntegerArray初始化完成
工作线程-0:获取到原子数组,长度:10
工作线程-1:获取到原子数组,长度:10
工作线程-2:获取到原子数组,长度:10
 (后续所有线程均获取到已初始化的数组,无重复初始化)
所有线程执行完成,原子数组最终状态:已初始化

方案2:使用静态内部类(懒汉式单例,更简洁安全)

利用 Java 类加载机制的线程安全性,
    通过静态内部类实现 `AtomicIntegerArray` 的懒加载(按需初始化),
     无需手动加锁,天然线程安全。

 核心原理
- 静态内部类 `AtomicArrayHolder` 不会在外部类加载时初始化,
     只有当调用 `getAtomicArray()` 方法时,才会加载内部类并初始化 `atomicArray`;
- Java 类加载器在加载静态内部类时,会保证初始化操作的原子性,
     多个线程同时调用时,只会有一个线程触发类加载,避免重复初始化;
- 无需手动使用 `volatile` 和同步锁,
     由 JVM 底层保证可见性和线程安全。
import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerArrayStaticInnerInit {
    // 私有化构造方法,避免外部实例化
    private AtomicIntegerArrayStaticInnerInit() {}

    /
      静态内部类:持有AtomicIntegerArray的实例,利用类加载机制保证线程安全
     /
    private static class AtomicArrayHolder {
        // 初始化AtomicIntegerArray,类加载时仅执行一次
        private static final AtomicIntegerArray ATOMIC_ARRAY = new AtomicIntegerArray(new int[]{1, 2, 3, 4, 5});
    }

    /
      多线程安全的判断与获取方法(判断逻辑隐含在类加载中)
     /
    public static AtomicIntegerArray getAtomicArray() {
        // 若内部类未加载,则触发加载并初始化ATOMIC_ARRAY;若已加载,直接返回已有实例
        return AtomicArrayHolder.ATOMIC_ARRAY;
    }

    /
      测试多线程环境下的初始化判断
     /
    public static void main(String[] args) throws InterruptedException {
        // 启动15个线程,并发获取原子数组
        for (int i = 0; i < 15; i++) {
            new Thread(() -> {
                AtomicIntegerArray array = getAtomicArray();
                System.out.println(Thread.currentThread().getName() + ":原子数组已初始化,索引0的值:" + array.get(0));
                // 验证线程安全:原子自增索引0的值
                array.incrementAndGet(0);
            }, "测试线程-" + i).start();
        }

        Thread.sleep(1000);
        // 打印最终结果,验证原子操作有效性
        System.out.println("最终索引0的值:" + getAtomicArray().get(0) + "(预期:1+15=16)");
    }
}

运行结果(天然线程安全,无重复初始化)

测试线程-0:原子数组已初始化,索引0的值:1
测试线程-1:原子数组已初始化,索引0的值:2
测试线程-2:原子数组已初始化,索引0的值:3
...
测试线程-14:原子数组已初始化,索引0的值:15
最终索引0的值:16(预期:1+15=16)

方案3:使用 AtomicReference(无锁方案,灵活度高)

 使用`AtomicReference` 封装 `AtomicIntegerArray` 引用,
     利用CAS原子操作实现无锁化的初始化判断与创建,
     避免锁竞争带来的性能开销。

 核心原理
- 用`AtomicReference` 存储 `AtomicIntegerArray`引用,
     保证引用更新的原子性;
- 通过`compareAndSet(null, newArray)` 实现“判断-初始化”的原子操作:
     只有当引用为 `null`时,
       才会创建新的 `AtomicIntegerArray` 并更新引用;
- 无需使用同步锁,
      通过 CAS 操作保证线程安全,适合高并发场景。
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicReference;

public class AtomicIntegerArrayAtomicRefInit {
    // 用AtomicReference封装AtomicIntegerArray引用,初始为null
    private static final AtomicReference<AtomicIntegerArray> ATOMIC_ARRAY_REF = new AtomicReference<>(null);

    /
      无锁化线程安全判断与初始化方法
     /
    public static AtomicIntegerArray getAtomicArray() {
        // 先获取当前引用
        AtomicIntegerArray atomicArray = ATOMIC_ARRAY_REF.get();
        
        // 第一次判断:若未初始化,进入CAS逻辑
        if (atomicArray == null) {
            // 创建新的AtomicIntegerArray实例(此处可自定义初始化逻辑)
            AtomicIntegerArray newArray = new AtomicIntegerArray(8);
            
            // CAS原子操作:只有当当前引用为null时,才会更新为newArray
            // 若更新成功,newArray即为初始化后的实例;若失败,说明其他线程已完成初始化
            boolean initSuccess = ATOMIC_ARRAY_REF.compareAndSet(null, newArray);
            
            if (initSuccess) {
                System.out.println(Thread.currentThread().getName() + ":CAS初始化AtomicIntegerArray成功");
                atomicArray = newArray;
            } else {
                System.out.println(Thread.currentThread().getName() + ":其他线程已完成初始化,直接获取");
                atomicArray = ATOMIC_ARRAY_REF.get();
            }
        }
        
        return atomicArray;
    }

    /
      多线程高并发测试
     /
    public static void main(String[] args) throws InterruptedException {
        // 启动30个线程,并发测试
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                AtomicIntegerArray array = getAtomicArray();
                System.out.println(Thread.currentThread().getName() + ":获取到原子数组,长度:" + array.length());
            }, "高并发线程-" + i).start();
        }

        Thread.sleep(1500);
        System.out.println("初始化状态:" + (ATOMIC_ARRAY_REF.get() != null ? "已完成" : "未完成"));
    }
}

运行结果(无锁安全,仅一次初始化成功)

高并发线程-0:CAS初始化AtomicIntegerArray成功
高并发线程-0:获取到原子数组,长度:8
高并发线程-1:其他线程已完成初始化,直接获取
高并发线程-1:获取到原子数组,长度:8
...(后续线程均直接获取已初始化的数组)
初始化状态:已完成
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaJingYan/202512/17666527038530.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者