最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java線程池中execute()和submit()兩個方法的區(qū)別(源碼&實戰(zhàn)全解析)

 更新時間:2026年03月21日 09:32:39   作者:J_liaty  
線程池是現代多線程編程中的重要工具,它能顯著提升任務處理效率并優(yōu)化系統(tǒng)資源,這篇文章主要介紹了Java線程池中execute()和submit()兩個方法區(qū)別的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

在 Java 并發(fā)編程中,線程池是核心技術之一,而 execute()submit() 是線程池最常用的兩個方法。很多開發(fā)者只停留在表面認識——execute 拋異常,submit 返回 Future,但這種理解遠遠不夠。

本文將從源碼層面深度解析這兩個方法的本質差異,并通過實戰(zhàn)案例演示它們的適用場景。

一、核心差異一覽

維度execute()submit()
返回值voidFuture
異常傳播任務內異常會直接拋出到 UncaughtExceptionHandler,主線程無法感知異常被 FutureTask 捕獲并存儲,調用 get() 時才拋出 ExecutionException
任務類型僅支持 Runnable支持 Runnable 和 Callable
適用場景不關心結果的異步任務(如日志發(fā)送、數據清理)需要獲取結果或處理異常的任務(如計算、RPC 調用)
接口定義Executor 接口ExecutorService 接口

二、源碼層面解析

2.1 submit() 的源碼實現

// AbstractExecutorService.java
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    // 關鍵點1:將 Runnable 包裝為 RunnableFuture
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);  // 關鍵點2:最終還是調用 execute()
    return ftask;    // 關鍵點3:返回 Future 對象
}

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

核心洞察submit() 本質上是 execute() 的包裝器,它在調用 execute() 前做了兩件事:

  1. 任務包裝:將 Runnable/Callable 包裝成 FutureTask
  2. 返回句柄:給調用者一個 Future 對象用于獲取結果

2.2 execute() 的核心邏輯

// ThreadPoolExecutor.java
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();

    int c = ctl.get();

    // 1. workerCount < corePoolSize -> 創(chuàng)建核心線程
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }

    // 2. workerCount >= corePoolSize && workQueue 未滿 -> 入隊
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (!isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }

    // 3. workerCount >= corePoolSize && workQueue 已滿 -> 創(chuàng)建非核心線程
    else if (!addWorker(command, false))
        // 4. 都失敗 -> 拒絕策略
        reject(command);
}

執(zhí)行流程

  • 工作線程數 < 核心線程數 → 創(chuàng)建核心線程執(zhí)行
  • 工作線程數 ≥ 核心線程數,隊列未滿 → 任務入隊
  • 工作線程數 ≥ 核心線程數,隊列已滿 → 創(chuàng)建非核心線程
  • 都失敗 → 觸發(fā)拒絕策略

三、實戰(zhàn)場景對比

3.1 異常處理的根本差異

execute() 的異常陷阱:

ExecutorService executor = Executors.newFixedThreadPool(2);

executor.execute(() -> {
    throw new RuntimeException("任務異常");
});

// 主線程無法捕獲這個異常!
// 異常會直接拋出到線程池的 UncaughtExceptionHandler

submit() 的異常安全:

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<?> future = executor.submit(() -> {
    throw new RuntimeException("任務異常");
});

try {
    future.get();  // 調用 get() 時才會拋出 ExecutionException
} catch (ExecutionException e) {
    System.out.println("捕獲到任務異常: " + e.getCause());
}

3.2 批量任務處理 - submit 優(yōu)勢場景

ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<Integer>> futures = new ArrayList<>();

// 提交多個任務
for (int i = 0; i < 10; i++) {
    final int num = i;
    futures.add(executor.submit(() -> compute(num)));
}

// 批量獲取結果
for (Future<Integer> future : futures) {
    try {
        System.out.println(future.get());
    } catch (Exception e) {
        System.out.println("任務執(zhí)行異常: " + e.getCause());
    }
}

private int compute(int num) {
    // 模擬計算任務
    return num * num;
}

3.3 超時控制 - submit 獨有能力

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<String> future = executor.submit(() -> {
    Thread.sleep(5000);
    return "結果";
});

try {
    String result = future.get(2, TimeUnit.SECONDS);  // 2秒超時
    System.out.println(result);
} catch (TimeoutException e) {
    future.cancel(true);  // 中斷任務
    System.out.println("任務超時,已取消");
}

3.4 execute 的最佳實踐 - 異常監(jiān)控

// 設置全局異常處理器
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
    System.out.println("線程 " + t.getName() + " 發(fā)生異常: " + e);
});

ExecutorService executor = Executors.newFixedThreadPool(2);

executor.execute(() -> {
    throw new RuntimeException("異常會被 UncaughtExceptionHandler 捕獲");
});

四、性能考量

  • execute():略輕量,直接提交任務,無需創(chuàng)建 FutureTask 對象
  • submit():因創(chuàng)建 FutureTask 有極小開銷,但在實際業(yè)務中差異可忽略
  • 建議:如果不需要返回值和異常處理,優(yōu)先使用 execute()

五、面試標準答案

問題: Java 線程池中 execute() 和 submit() 有什么區(qū)別?

標準回答:

  1. 核心差異:execute() 是 Executor 接口定義的基礎方法,用于提交不需要返回值的任務;submit() 是 ExecutorService 擴展的方法,可以提交 Callable/Runnable 并返回 Future 對象。

  2. 源碼層面:submit() 內部將任務包裝成 FutureTask,然后調用 execute() 執(zhí)行,所以 execute() 是 submit() 的底層實現。

  3. 異常處理:這是最重要的區(qū)別——execute() 中任務的異常會直接拋出到線程池的異常處理器,主線程無法感知;submit() 中任務的異常被 FutureTask 捕獲存儲,只有調用 Future.get() 時才會拋出 ExecutionException,主線程可以統(tǒng)一處理。

  4. 適用場景:execute() 適合"提交即忘"的異步任務(如日志、清理);submit() 適合需要結果、超時控制或細粒度異常處理的任務。

  5. 性能考量:execute() 略輕量,submit() 因為創(chuàng)建 FutureTask 有極小開銷,但在實際業(yè)務中差異可忽略。

六、進階思考

6.1 為什么 submit() 要返回 Future?

這是"控制權"的設計哲學,調用者可以通過 Future 實現取消、超時、結果獲取等精細控制。

6.2 線程池的拒絕策略對兩者有區(qū)別嗎?

沒有,最終都是調用 execute(),拒絕策略統(tǒng)一生效。

6.3 如何既用 execute() 的輕量,又實現異常監(jiān)控?

可以自定義 ThreadPoolExecutor,重寫 afterExecute() 方法:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, 4, 60, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>()
) {
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t != null) {
            System.out.println("任務執(zhí)行異常: " + t);
        } else if (r instanceof Future<?>) {
            try {
                ((Future<?>) r).get();
            } catch (Exception e) {
                System.out.println("Future 異常: " + e.getCause());
            }
        }
    }
};

七、總結

這道題的深層考點是:是否理解 Java 并發(fā)框架中"任務"和"執(zhí)行"的分離設計,以及異常在不同線程上下文中的傳播機制。

  • execute():輕量級異步執(zhí)行,適合"提交即忘"場景
  • submit():功能完善,支持結果獲取、超時控制、異常統(tǒng)一處理

選擇建議

  • 不需要返回值 → 優(yōu)先 execute()
  • 需要返回值或異常處理 → 必須使用 submit()

到此這篇關于Java線程池中execute()和submit()兩個方法區(qū)別的文章就介紹到這了,更多相關Java線程池execute()和submit()區(qū)別內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 詳解 maven的pom.xml用<exclusion>解決版本問題

    詳解 maven的pom.xml用<exclusion>解決版本問題

    這篇文章主要介紹了詳解 maven的pom.xml用<exclusion>解決版本問題的相關資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Java中的jinfo命令使用詳解

    Java中的jinfo命令使用詳解

    jinfo是JDK提供的一個可以實時查看Java虛擬機各種配置參數和系統(tǒng)屬性的命令行工具,本文給大家介紹下Java中的jinfo命令使用,感興趣的朋友一起看看吧
    2022-03-03
  • Spring BeanDefinition使用介紹

    Spring BeanDefinition使用介紹

    BeanDefinition是Spring框架中非常核心的概念,BeanDefinition是定義Bean的配置元信息接口,Spring根據BeanDefinition來定義Bean對象,簡單說就是對Bean信息的定義
    2023-01-01
  • java的繼承原理與實現方法詳解

    java的繼承原理與實現方法詳解

    這篇文章主要介紹了java的繼承原理與實現方法,結合實例形式詳細分析了Java繼承的概念、原理、用法及相關操作注意事項,需要的朋友可以參考下
    2019-05-05
  • Mybatis使用大于等于或小于等于進行比較

    Mybatis使用大于等于或小于等于進行比較

    本文主要介紹了Mybatis使用大于等于或小于等于進行比較,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • SpringBoot?整合Security權限控制的初步配置

    SpringBoot?整合Security權限控制的初步配置

    這篇文章主要為大家介紹了SpringBoot?整合Security權限控制的初步配置實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • javaweb中Filter(過濾器)的常見應用

    javaweb中Filter(過濾器)的常見應用

    這篇文章主要介紹了javaweb中Filter的常見應用,過濾器的使用方法,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Java編程實現深度優(yōu)先遍歷與連通分量代碼示例

    Java編程實現深度優(yōu)先遍歷與連通分量代碼示例

    這篇文章主要介紹了Java編程實現深度優(yōu)先遍歷與連通分量代碼示例,
    2017-11-11
  • Java的方法和this關鍵字如何理解與應用

    Java的方法和this關鍵字如何理解與應用

    Java語言中的“方法”(Method)在其他語言當中也可能被稱為“函數”(Function)。對于一些復雜的代碼邏輯,如果希望重復使用這些代碼,并且做到“隨時任意使用”,那么就可以將這些代碼放在一個大括號{}當中,并且起一個名字。使用代碼的時候,直接找到名字調用即可
    2021-10-10
  • AndroidHttpClient使用Cookie應用分析

    AndroidHttpClient使用Cookie應用分析

    今天想把一個用使用了HttpClient的自動簽到小程序移植到Android上,還好Android的SDK自帶了HttpClient的包.當然也可以繼續(xù)使用DefaultHttpClient,但用為Android定制的AndroidHttpClient自然更好
    2012-11-11

最新評論

洛南县| 吕梁市| 溧水县| 庆安县| 从化市| 封丘县| 桐城市| 云安县| 蒙城县| 通许县| 嘉峪关市| 蛟河市| 神池县| 宿迁市| 榆社县| 望江县| 浏阳市| 张家界市| 新源县| 江孜县| 潍坊市| 阿拉尔市| 铜鼓县| 西乡县| 淄博市| 油尖旺区| 滦平县| 肇州县| 汉川市| 东乡族自治县| 永州市| 遂宁市| 东源县| 四川省| 南和县| 青川县| 景德镇市| 宝丰县| 怀来县| 孟津县| 留坝县|