Java 自 1995 年問世以來,憑藉簡單性、面向對象、平台無關性及多線程支持等優勢,迅速成為全球最熱門的程式語言之一。在 GUI 應用開發中,妥善處理耗時任務而不凍結介面,是提升用戶體驗的關鍵。本文將示範如何利用 Java 多線程機制,實現一個「正在執行,請等待」的非阻塞提示框。
在 Java 桌面應用中,若在事件分派執行緒(EDT)上直接執行大量資料庫交換、複雜運算或遠程伺服器連線等耗時操作,會導致介面無法重繪、滑鼠點擊無響應,甚至出現「未回應」的假象。這在專業軟體中是不可接受的。
採用「工作者執行緒 + 提示框執行緒 + 監控執行緒」三線程協作模式:
JDialog 顯示等待資訊,並將游標設為等待狀態。Thread.join() 等待工作者執行緒結束,隨後自動關閉提示框。此架構確保 EDT 始終保持響應,同時提示框能準確反映後台任務狀態。
TestFrame建立包含「開始執行緒」按鈕的主視窗,按鈕事件中啟動三個執行緒:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestFrame extends JFrame {
private JPanel testPanel;
private JButton testButton;
public TestFrame() {
// 設定 Windows 外觀
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ex) {
System.out.println("LookAndFeel 設定失敗: " + ex);
}
// 視窗置中、尺寸為螢幕一半
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
setSize(dim.width / 2, dim.height / 2);
setLocation(dim.width / 4, dim.height / 4);
testPanel = new JPanel();
testButton = new JButton("開始執行緒");
testPanel.add(testButton);
getContentPane().add(testPanel);
// 按鈕事件:啟動工作者執行緒、提示框執行緒
testButton.addActionListener(e -> {
TestThread worker = new TestThread();
worker.start();
new ThreadDiag(this, worker, "正在執行,請等待......").start();
});
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TestFrame f = new TestFrame();
f.setTitle("執行緒等待測試");
f.setVisible(true);
});
}
}
TestThread模擬耗時運算:在標準輸出列印 1 到 99999。
public class TestThread extends Thread {
@Override
public void run() {
for (int i = 1; i < 100000; i++) {
System.out.println(i);
}
}
}
ThreadDiag建立模態對話框,啟動監控執行緒 DisposeDiag。
import javax.swing.*;
import java.awt.*;
public class ThreadDiag extends Thread {
private final Thread workerThread;
private final JFrame parent;
private final String message;
private JDialog dialog;
public ThreadDiag(JFrame parent, Thread workerThread, String message) {
this.parent = parent;
this.workerThread = workerThread;
this.message = message;
initDialog();
}
private void initDialog() {
dialog = new JDialog(parent, "正在執行,請等待...", true);
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
JPanel panel = new JPanel();
panel.add(new JLabel(message));
dialog.getContentPane().add(panel);
new DisposeDiag(workerThread, dialog).start(); // 監控執行緒
}
@Override
public void run() {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = dim.width / 4, h = 60;
dialog.setSize(w, h);
dialog.setLocation((dim.width - w) / 2, (dim.height - h) / 2);
dialog.setVisible(true); // 阻塞直到 dispose()
}
}
DisposeDiag等待工作者執行緒結束,然後釋放提示框資源。
class DisposeDiag extends Thread {
private final Thread target;
private final JDialog dialog;
public DisposeDiag(Thread target, JDialog dialog) {
this.target = target;
this.dialog = dialog;
}
@Override
public void run() {
try {
target.join(); // 等待工作者結束
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
SwingUtilities.invokeLater(() -> dialog.dispose());
}
}
}
點擊按鈕後,中央顯示「正在執行,請等待......」模態對話框,主視窗仍可移動、最小化;控制檯高速輸出數字。當迴圈結束,對話框自動消失,程式恢復正常互動。

此範例展示了經典的「背景執行緒 + 玻璃窗/模態對話框」模式,適用於 JDK 1.3 及以上版本。實務上可進一步封裝為可復用的 WaitingDialog 工具類,支援進度條、取消操作等進階功能。