首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

J2ME 多執行緒網路連線程式設計深度解析

     編輯:Java 相關知識

歷史背景:為什麼當年要在功能機上寫多執行緒?

J2ME (Java ME) 是 2000 年代功能機、早期智慧型手機的主流開發平台。裝置記憶體只有 1-2 MB、CPU 極慢、網路延遲高且不穩。若在主執行緒 (MIDlet 主事件迴路) 直接呼叫 Connector.open() 進行 HTTP 連線,畫面會凍結數秒甚至分鐘,使用者無法操作、甚至被系統判定為「當機」強制關閉。因此多執行緒不是優化,是生存門檻。

GCF (Generic Connection Framework) 架構速覽

javax.microedition.io 定義了分層介面:

  • Connection → StreamConnection → ContentConnection → HttpConnection
  • DatagramConnection (UDP)
  • SocketConnection (TCP)

MIDP 1.0 強制實作 HTTP;MIDP 2.0 新增 HTTPS。所有 I/O 皆為阻塞式,必須另開執行緒。

三種多執行緒模式比較

1. 簡易 Thread + Runnable(最常見)

public void commandAction(Command c, Displayable d) {
    if (c == sendCmd) new Thread(new NetWorker()).start();
}

class NetWorker implements Runnable {
    public void run() {
        HttpConnection hc = null;
        try {
            hc = (HttpConnection) Connector.open(url);
            int rc = hc.getResponseCode();
            if (rc == HttpConnection.HTTP_OK) {
                // 讀取資料...
                display.setCurrent(resultForm); // 切換 UI 必須在事件執行緒
            }
        } catch (IOException e) { /* 錯誤處理 */ }
        finally { if (hc != null) try { hc.close(); } catch (IOException ignore) {} }
    }
}

缺點:使用者連點兩次按鈕會產生兩條執行緒,資源浪費且可能競爭。

2. 單一背景執行緒 + wait/notify 同步(生產級)

class NetDispatcher implements Runnable {
    private boolean busy = false;
    private String pendingUrl;
    private final Object lock = new Object();

    public void dispatch(String url) {
        synchronized (lock) {
            pendingUrl = url;
            if (!busy) { busy = true; new Thread(this).start(); }
            else lock.notify(); // 喚醒既有執行緒
        }
    }

    public void run() {
        while (true) {
            String url;
            synchronized (lock) {
                while (pendingUrl == null) {
                    try { lock.wait(); } catch (InterruptedException ignore) {}
                }
                url = pendingUrl; pendingUrl = null;
            }
            doRequest(url); // 實際連線邏輯
            synchronized (lock) { if (pendingUrl == null) { busy = false; break; } }
        }
    }
}

優點:同一時間只有一條網路執行緒,請求自動排隊,無競爭、無洩漏。

3. Timer + TimerTask 定時輪詢(適用於長連線/心跳)

class HeartbeatTask extends TimerTask {
    private final Timer timer = new Timer();
    public void start() { timer.schedule(this, 0, 30_000); } // 30 秒一次
    public void run() { sendHeartbeat(); }
    public void stop() { timer.cancel(); }
}

注意:Timer 內部只有一條執行緒,任務若阻塞會延遲後續任務;網路請求建議仍用專屬執行緒池。

關鍵最佳實踐(至今仍適用於 Android/嵌入式)

  1. 所有網路 I/O 禁絕在事件派發執行緒 (EDT/UI Thread)。
  2. 連線逾時必須設定:hc.setRequestProperty("Connection", "close"); 避免 Keep-Alive 卡死。
  3. 資源釋放用 finally 區塊:InputStream/OutputStream/HttpConnection 全部關閉。
  4. UI 更新回主執行緒:J2ME 用 Display.callSerially(Runnable),Android 用 runOnUiThread/Handler,Swing 用 SwingUtilities.invokeLater。
  5. 取消機制:提供 cancel() 讓使用者可中止長連線,釋放資源。

結語

雖然 J2ME 已成歷史,但「阻塞 I/O 必須離開主執行緒、生產者/消費者模式解耦請求與執行、生命週期管理防洩漏」這三大原則,放在現代 Android、Java SE、嵌入式 Java 開發依然完全通用。理解當年的約束,更能體會今天 CompletableFuture、RxJava、Coroutines 設計的精妙。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved