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()机制:
- 在
Gioco里加一个private boolean isFinished = false;的成员变量,配合同步锁使用。 - 在
fine()里设置isFinished = true;,然后调用notifyAll();:
private void fine() { // ... 原有逻辑 ... synchronized(this) { isFinished = true; notifyAll(); } }
- 在
Gioco里新增同步等待方法:
public synchronized void waitForFinish() throws InterruptedException { while (!isFinished) { wait(); } }
- 在
Gioca的gioca()方法里替换join()为等待逻辑:
t.start(); ((Gioco)t.getTarget()).waitForFinish();
两种方案都能解决你的问题,CountDownLatch更简洁,适合这种一次性等待的场景。
内容的提问来源于stack exchange,提问作者Marco Rocchi
相关产品推荐
相关产品推荐

