Java執行緒池中的execute和submit

衛旗發表於2023-02-01

一、概述

execute和submit都是執行緒池中執行任務的方法。

execute是Executor介面中的方法

public interface Executor {

    void execute(Runnable command);
}

submit是ExecuteService介面中的方法。

public interface ExecutorService extends Executor {

    <T> Future<T> submit(Callable<T> task);
  
    <T> Future<T> submit(Runnable task, T result);
   
    Future<?> submit(Runnable task);
}

透過原始碼可以看出execute方法無返回值,引數為Runnable物件。
submit方法有三個過載方法,都有Future型別的返回值,引數可以是Runnable物件,Callable物件,Runnable物件和一個其他型別的物件。

那麼在執行過程中有異常丟擲會怎麼樣呢,先說答案,execute方法會直接丟擲異常,submit方法不會丟擲異常,只有在透過Future的get方法獲取結果的時候才會丟擲異常,下面進行測試:

public class ExecutorTest1 {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        executorService.execute(() -> test1.say("execute方法"));
        executorService.submit(() -> test1.say("submit方法"));
        executorService.shutdown();
    }

    private void say(String msg){
        System.out.println(msg);
        throw new RuntimeException("丟擲了異常:"+ msg);
    }
}

執行結果如下:

image.png
可見execute方法直接丟擲了異常,submit方法只列印了引數沒有丟擲異常,下面測試使用Future的get方法獲取結果:

public class ExecutorTest1 {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        executorService.execute(() -> test1.say("execute方法"));
        Future<?> submitFuture = executorService.submit(() -> test1.say("submit方法"));
        try {
            Object o = submitFuture.get();
            System.out.println("這是submit的返回值:"+o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

    private void say(String msg){
        System.out.println(msg);
        throw new RuntimeException("丟擲了異常:"+ msg);
    }
}

結果如下:

image.png
可見使用submit方法時只有在使用Future的get方法時才會丟擲異常,並且get方法也會丟擲ExecutionException異常。
那麼還有一個問題,如果執行緒中執行方法丟擲的異常已經被捕獲了,那麼submit會怎麼處理呢,其實在方法中如果異常已經被捕獲了,那麼就是方法的正常執行,有異常列印的話在執行的時候就會列印,不會等到呼叫Future的get方法時候才會列印。測試如下:

public class ExecutorTest1 {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        executorService.execute(() -> test1.say("execute方法"));
        Future<?> submitFuture = executorService.submit(() -> test1.say("submit方法"));
        try {
            Object o = submitFuture.get();
            System.out.println("這是submit的返回值:"+o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

    private void say(String msg){
        System.out.println(msg);
        try{
            throw new RuntimeException("丟擲了異常:"+ msg);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

結果如下:

image.png
可見execute和submit都正常執行了方法,Future的get方法也獲取到了結果,因為say方法沒有返回值,所以列印的結果是null。

二、結論

execute和submit的區別如下:

  1. execute是Executor介面的方法,submit是ExecuteService介面的方法。
  2. execute的入參是Runnable,submit的入參可以是Runnable、Callable、Runnable和一個返回值。
  3. execute沒有返回值,submit有返回值。
  4. 方法中丟擲異常,execute會直接丟擲異常,submit會在獲取結果的時候丟擲異常,如果不獲取結果,submit不丟擲異常。




關於Future可以檢視:
Java多執行緒:Future和FutureTask

之前文章:

HashMap原始碼解析(基於JDK1.8)

Java執行緒池詳解

相關文章