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

Java 線程創建基礎:Runnable 接口實現詳解與最佳實踐

     編輯:Java 程式設計入門

前言

實現 Runnable 接口是 Java 創建線程的標準方式之一,它將「任務邏輯」與「線程控制」解耦,支援線程池提交、Lambda 表達式、函數式編程,是現代並發編程的推薦範式。本文通過完整代碼示例,講解實現步驟、構造方法選擇、命名規範、常見誤區。

一、核心步驟

  1. 定義類實現 Runnable,重寫 run() 方法編寫任務邏輯。
  2. 實例化該任務類對象。
  3. 創建 Thread 實例,將任務對象傳入構造器。
  4. 調用 thread.start() 啟動線程(不是 run())。

二、完整代碼示例

package com.example.thread;

public class RunnableDemo {

    static class MyTask implements Runnable {
        private final String taskName;

        public MyTask(String taskName) {
            this.taskName = taskName;
        }

        @Override
        public void run() {
            // 任務邏輯
            for (int i = 1; i <= 3; i++) {
                System.out.printf("[%s] %s - Step %d%n",
                        Thread.currentThread().getName(), taskName, i);
                try { Thread.sleep(200); } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // 重置中斷標誌
                    return; // 優雅退出
                }
            }
        }
    }

    public static void main(String[] args) {
        // 1. 創建任務實例(可復用)
        MyTask task1 = new MyTask("訂單處理");
        MyTask task2 = new MyTask("庫存扣減");

        // 2. 創建線程並指定名稱(生產環境強烈建議)
        Thread t1 = new Thread(task1, "Order-Thread-1");
        Thread t2 = new Thread(task2, "Stock-Thread-1");

        // 3. 啟動線程
        t1.start();
        t2.start();

        // 4. 主線程等待子線程結束(演示用,實際用線程池)
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("主線程結束");
    }
}

三、關鍵點深度解析

1. 構造方法選擇

// 僅傳任務,線程名自動分配 "Thread-N"
new Thread(runnable)

// 傳任務 + 顯式線程名(推薦)
new Thread(runnable, "Business-Name-1")

// 傳線程組 + 任務 + 名稱(罕用)
new Thread(threadGroup, runnable, "Name")

線程名規範:業務模塊-功能-序號,如 Order-PayCallback-3,便於 jstack/Arthas/日誌排查。

2. 任務對象復用:單對象多線程

Runnable sharedTask = () -> System.out.println("Shared: " + Thread.currentThread().getName());
new Thread(sharedTask, "T1").start();
new Thread(sharedTask, "T2").start();
new Thread(sharedTask, "T3").start();

三線程共享同一 Runnable 實例,若任務內有非線程安全狀態(如計數器),必須自行同步(synchronized/AtomicInteger)。

3. Lambda 表達式簡化(Java 8+)

// 匿名內部類等價
new Thread(() -> {
    System.out.println("Lambda 任務運行中...");
    // 多行邏輯
}, "Lambda-Thread").start();

4. 常見錯誤:直接調用 run()

// 錯誤!在主線程同步執行,不會創建新線程
new Thread(task).run();

// 正確
new Thread(task).start();

四、對比:Runnable vs Thread 繼承

維度Runnableextends Thread
繼承限制無,可繼承其他類單繼承,無法復用邏輯
任務復用同一實例可提交多線程/線程池每線程需 new 子類實例
線程池兼容原生支援 executor.submit(runnable)需包裝或改寫
Lambda 支援函數式接口,完美適配不支援
訪問線程屬性需 Thread.currentThread()直接 this.getName()

五、生產環境建議:拋棄手動創建,擁抱線程池

// 定義線程池(實際應配置化、監控化)
ExecutorService pool = new ThreadPoolExecutor(
    4, 8, 60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100),
    new ThreadFactoryBuilder().setNameFormat("Biz-Worker-%d").build(),
    new ThreadPoolExecutor.AbortPolicy()
);

// 提交 Runnable 任務
pool.submit(() -> {
    // 業務邏輯
    return result; // 若需返回值用 Callable
});

// 關閉
pool.shutdown();

手動 new Thread 缺點:無限制創建導致 OOM、無隊列緩衝、無拒絕策略、無監控指標、線程名不可控。

六、總結

  • Runnable 將任務與線程分離,是並發編程的基石。
  • 掌握構造器選擇、線程命名、Lambda 簡化、任務復用與同步。
  • 實際項目中直接使用線程池提交 Runnable/Callable,手動 new Thread 僅用於簡單測試或特殊場景(如需要繼承 Thread 重寫 interrupt())。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved