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

Java多线程下跨类传递变量获取null的解决方案

以下为我开发的多线程项目的高度简化版本,用于以最简形式复现问题,便于理解排查。

项目包含两个类:startSession.java 与 main.java。
我需要在多线程模式下将变量从startSession.java传递到main.java,但目前遇到问题:每次在main类中尝试获取该变量时,返回值均为null。
startSession类中包含run()方法、Setter方法setSessionKey(String sess)与Getter方法getSessionKey(),我使用硬编码变量开展测试。
get方法仅在run()方法内部调用时可正常取值,在main方法中调用getSessionKey()会返回null,运行结果见下方截图。该问题仅在多线程场景下出现:若不使用多线程,直接在main方法中调用run()方法,则可正常获取非null的目标变量值。

请问在多线程场景下,如何实现变量从startSession类到main类的正确传递?


问题相关代码

startSession.java

public class startSession extends Thread {

    static String sessionKey;

    public void run() {
        String createdSession = "83248329";
        setSessionKey(createdSession);
        System.out.println("Inside run method: " + getSessionKey());
    }

    public String getSessionKey() {
        return sessionKey;
    }

    public void setSessionKey(String sess) {
        sessionKey = sess;
    }
}

main.java

package com.Server;

public class Main {

    static String session;

    public static void main(String[] args) throws InterruptedException {
        startSession startSession = new startSession();

        startSession.start();

        session = startSession.getSessionKey();
        System.out.println("Inside Main: " + session);
    }
}

运行结果

  • 多线程模式运行结果:
    多线程运行结果截图
  • 非多线程模式运行结果:
    非多线程运行结果截图

问题根因

这是最基础的多线程并发时序+可见性问题,和变量传值逻辑无关:

  1. 调用Thread.start()启动子线程后,子线程的run()方法和主线程后续代码是并行执行的,不存在强制先后顺序。你在主线程中立刻调用getSessionKey()时,子线程大概率还没执行到给sessionKey赋值的逻辑,自然拿到的是成员变量的初始值null。
  2. 直接在主线程调用run()方法属于同步调用,代码按顺序逐行执行,赋值逻辑完成后才会走取值逻辑,所以能拿到正确结果。
  3. 你当前代码里把sessionKey定义为static是错误设计:静态变量属于类所有,不属于单个线程实例,后续创建多个startSession实例时会出现值互相覆盖的问题,应该改为实例私有成员变量。
  4. 就算调整时序让子线程先赋值,没有正确的同步手段的话,主线程也可能因为CPU缓存看不到子线程的修改,出现可见性问题。

修复方案

最简场景下直接使用Thread.join()即可,这个方法会阻塞调用方线程(这里是主线程),直到子线程执行完毕,同时自带Happens-Before内存可见性保证,子线程对变量的所有修改都会对主线程可见,不需要额外加volatile或者锁。

修正后代码

  1. 修正startSession类,去掉不合理的static修饰:
public class startSession extends Thread {
    // 改为实例私有变量,避免多实例值互相覆盖
    private String sessionKey;

    public void run() {
        String createdSession = "83248329";
        setSessionKey(createdSession);
        System.out.println("Inside run method: " + getSessionKey());
    }

    public String getSessionKey() {
        return sessionKey;
    }

    public void setSessionKey(String sess) {
        sessionKey = sess;
    }
}
  1. 修正Main类,加join()等待子线程执行完成再取值:
package com.Server;

public class Main {

    static String session;

    public static void main(String[] args) throws InterruptedException {
        startSession startSession = new startSession();
        startSession.start();
        // 阻塞主线程,直到子线程执行完毕
        startSession.join();
        session = startSession.getSessionKey();
        System.out.println("Inside Main: " + session);
    }
}

如果后续业务不需要等子线程完全执行完,只需要等sessionKey赋值完成就可以继续后续逻辑,可以使用CountDownLatch、FutureTask等并发工具实现更细粒度的等待控制,不需要死等线程结束。

补充:Java编码规范要求类名使用大驼峰命名,startSession建议重命名为StartSession,main类类名已经是Main符合规范。


内容的提问来源于stack exchange,提问作者Crimson Space

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:24:09