首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java Swing 呼叫 go() 死循環導致介面凍結:EDT 執行緒阻塞與多執行緒修正

     編輯:程式設計綜合問答

問題現象

在 ActionListener 中直接呼叫 go(),其中包含 while(true) 迴圈與 Thread.sleep(10),導致整個視窗凍結,無法重繪、無法響應按鈕。

根本原因

Swing 為**單執行緒模型**,所有事件處理、繪圖均在 **Event Dispatch Thread (EDT)** 執行。go() 佔用 EDT 導致訊息佇列堵塞,無法處理 repaint()、滑鼠/鍵盤事件。

修正方案:將耗時任務移至背景執行緒

public void actionPerformed(ActionEvent e) {
    // 啟動背景執行緒
    new Thread(() -> {
        go(); // 此處執行耗時迴圈
    }, "Lottery-Loop").start();
}

// go() 內部需安全更新 UI 元件
public void go() {
    while (true) {
        if (isGo) {
            String s = generateNumber();
            // 必須在 EDT 更新 Swing 元件
            SwingUtilities.invokeLater(() -> tf.setText(s));
        }
        try { Thread.sleep(10); } catch (InterruptedException ignored) {}
    }
}

進階:使用 SwingWorker (可取消、進度回報)

private SwingWorker worker = new SwingWorker<>() {
    @Override
    protected Void doInBackground() {
        while (!isCancelled()) {
            if (isGo) {
                publish(generateNumber()); // 發送中間結果
            }
            try { Thread.sleep(10); } catch (InterruptedException ignored) {}
        }
        return null;
    }
    @Override
    protected void process(List chunks) {
        tf.setText(chunks.get(chunks.size() - 1)); // 只顯示最新
    }
};

// 啟動
worker.execute();
// 停止
worker.cancel(true);

關鍵守則

  1. **絕不在 EDT 執行耗時/阻塞操作** (睡眠、IO、大量計算、死迴圈)。
  2. 背景執行緒更新 UI **必須**透過 SwingUtilities.invokeLater、SwingWorker.publish/process 或 EventQueue.invokeLater。
  3. 長時間任務提供**取消機制** (isCancelled()、interrupt()) 避免資源洩漏。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved