在 JavaFX 應用程式開發中,當主視窗關閉時,預設情況下 JVM 不會自動終止仍在執行的背景執行緒。這會導致程式看似已關閉,實際上進程仍殘留在記憶體中繼續消耗資源。特別是當背景執行緒持有資料庫連線、檔案控制代碼或網路連接時,更會造成資源洩漏與資料不一致風險。
JavaFX 提供 setOnCloseRequest() 方法,允許開發者在視窗關閉前插入自定義邏輯,例如通知背景執行緒安全停止、釋放資源、儲存狀態等。
package sample;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Main extends Application {
// 模擬背景執行緒
private BackgroundWorker backgroundWorker = new BackgroundWorker();
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("JavaFX 關閉事件示範");
primaryStage.setScene(new Scene(root, 400, 300));
primaryStage.show();
// 核心:註冊視窗關閉事件監聽器
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
System.out.println("偵測到視窗關閉請求,開始優雅關閉流程...");
// 1. 通知背景執行緒停止
backgroundWorker.shutdown();
// 2. 等待執行緒實際結束(可設定超時)
try {
backgroundWorker.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("背景執行緒已安全停止,程式即將退出");
}
});
}
public static void main(String[] args) {
launch(args);
}
}
// 模擬背景工作執行緒
class BackgroundWorker {
private volatile boolean running = true;
private Thread workerThread;
public BackgroundWorker() {
workerThread = new Thread(() -> {
while (running) {
try {
System.out.println("背景執行緒執行中... " + new Date());
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println("背景執行緒已退出迴圈");
});
workerThread.start();
}
public void shutdown() {
running = false;
workerThread.interrupt();
}
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
workerThread.join(unit.toMillis(timeout));
return !workerThread.isAlive();
}
}
// 核心監聽器註冊
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
System.out.print("監聽到視窗關閉");
// 在此處執行清理邏輯
}
});
當使用者點擊視窗右上角關閉按鈕時,控制台輸出:
偵測到視窗關閉請求,開始優雅關閉流程... 背景執行緒已安全停止,程式即將退出

dataSource.close() 釋放所有連線scheduler.shutdown() 停止排程器LogManager.shutdown() 確保日誌完整寫入@PreDestroy 或 DisposableBean 統一管理生命週期正確處理視窗關閉事件是開發穩健 JavaFX 桌面應用的基本功,能有效避免「關不掉的程式」與資源洩漏問題,提升使用者體驗與系統穩定度。