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

Java线程join未等待线程退出问题排查

问题分析与解决

你遇到的问题核心在于**Gioco线程的run()方法并没有一直运行到游戏结束**,而你调用的t.join()只是等待这个线程的run()方法执行完毕,不是等待fine()被调用。

为什么Campana例子正常?

在Campana的代码里,线程的run()方法包含了所有要执行的核心逻辑(循环打印5次),线程会一直运行到循环结束,所以join()会等待整个任务完成后才继续执行后续代码。

你的代码为什么失效?

看Gioco的run()方法:

@Override
public void run() {
    f.setVisible(true);
    timer.start();
}

这个方法只做了两件事:显示窗口、启动Timer,然后方法就执行完了,线程直接结束。而Timer是Swing的定时器,它是在Swing的事件调度线程(EDT)里执行actionPerformed逻辑的,和你创建的Gioco线程完全是两个独立的线程。所以你的t.join()等待的只是run()方法执行完毕,这几乎是瞬间完成的,自然会立刻打印"Fine",而此时游戏还在运行。

解决方案:用同步机制等待fine()被调用

我们可以给Gioco类加一个同步的等待机制,让Gioca线程能等到fine()被调用后再继续。这里推荐用CountDownLatch,简单直观:

步骤1:修改Gioco类

import java.util.concurrent.CountDownLatch;

public class Gioco extends Canvas implements ActionListener, KeyListener, Runnable {
    // 新增一个CountDownLatch,计数为1,代表等待游戏结束这一个事件
    private CountDownLatch endLatch;
    // ... 保留其他原有成员变量 ...

    // 修改构造方法,接收CountDownLatch参数
    public Gioco(int vite, CountDownLatch endLatch) {
        this.endLatch = endLatch;
        // ... 保留原有构造逻辑 ...
    }

    // 修改fine()方法,在最后触发计数递减,通知等待线程
    private void fine() {
        try {
            Thread.sleep(3000);
        } catch(Exception e){}
        timer.stop();
        try {
            File file=new File("images/punteggio.txt");
            file.createNewFile();
            FileOutputStream f=new FileOutputStream(file);
            f.flush();
            String sPunteggio=String.valueOf(spazio);
            byte[] scrivi=sPunteggio.getBytes();
            f.write(scrivi);
        } catch(Exception e){}
        f.dispose();
        // 通知等待的线程:游戏结束了
        endLatch.countDown();
    }

    // ... 保留其他原有方法不变 ...
}

步骤2:修改Gioca类的gioca()方法

public void gioca() {
    // 创建CountDownLatch,初始计数为1
    CountDownLatch endLatch = new CountDownLatch(1);
    Thread t=new Thread(new Gioco(vite, endLatch));
    try {
        t.start();
        // 等待CountDownLatch的计数变为0,也就是fine()被调用
        endLatch.await();
    } catch (Exception ex) {
        ex.printStackTrace(); // 建议不要空捕获异常,至少打印异常信息方便排查
    }
    System.out.println("Fine");
}

其他可选方案

如果你不想用CountDownLatch,也可以用传统的wait()/notify()机制:

  1. 在Gioco里加一个private boolean isFinished = false;的成员变量,配合同步锁使用。
  2. 在fine()里设置isFinished = true;,然后调用notifyAll();:
private void fine() {
    // ... 原有逻辑 ...
    synchronized(this) {
        isFinished = true;
        notifyAll();
    }
}
  1. 在Gioco里新增同步等待方法:
public synchronized void waitForFinish() throws InterruptedException {
    while (!isFinished) {
        wait();
    }
}
  1. 在Gioca的gioca()方法里替换join()为等待逻辑:
t.start();
((Gioco)t.getTarget()).waitForFinish();

两种方案都能解决你的问题,CountDownLatch更简洁,适合这种一次性等待的场景。

内容的提问来源于stack exchange,提问作者Marco Rocchi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:35:04