You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何仅创建一个对象,Thread却检测到两个实例?

问题分析

代码示例

public class ThreadExample {

    public static ArrayList<ThreadExample> instances = new ArrayList<ThreadExample>();

    public ThreadExample() {
        instances.add(this);
    }

    public static void main(String[] args) {
        ThreadRead threadRead = new ThreadRead();
        ThreadCreate threadCreate = new ThreadCreate();
        threadCreate.start();
        threadRead.start();

    }

}

class ThreadRead extends Thread {
    public void run() {
        System.out.println(ThreadExample.instances.size());
    }
}

class ThreadCreate extends Thread {
    public void run() {
        ThreadExample.instances.add(new ThreadExample());
    }
}

问题描述

该代码运行输出为"2",但预期输出应为1或0:若ThreadCreate线程创建对象时ThreadRead线程同时读取,可能因对象构造未完成读到0;若执行正常则读到1。想请教其中未知的原因是什么?

原因解析

你忽略了一个关键细节:ThreadExample的构造函数里已经调用了instances.add(this),而ThreadCreate的run方法中又额外执行了一次ThreadExample.instances.add(new ThreadExample())。

当ThreadCreate线程执行new ThreadExample()时,会先触发构造函数,此时instances会添加当前实例(size变为1);构造函数执行完成后,run方法里的add语句会再次把刚刚创建的实例添加到instances中(size变为2)。这两个操作在同一个线程内是顺序执行的,不存在线程安全问题,所以只要ThreadCreate线程的run方法执行完毕,instances的大小就一定是2。

如果ThreadRead线程在ThreadCreate线程完成这两次add操作之后才读取,就会输出2;如果ThreadRead在ThreadCreate开始执行前就读取,会输出0;但由于线程调度的不确定性,输出2是完全合理的结果——因为ThreadCreate的两次add是原子性的(同一线程内顺序执行),不会出现读到1的情况。

另外需要补充:ArrayList本身不是线程安全的集合,即使没有构造函数里的额外add,多线程下读写也可能出现不一致,但这个案例里的核心问题是重复添加的逻辑错误,而非线程安全问题。

内容的提问来源于stack exchange,提问作者MUSA BEYTEKİN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 19:57:10