切換語言為:簡體
Java執行緒池遇到未處理的異常會崩潰嗎?

Java執行緒池遇到未處理的異常會崩潰嗎?

  • 爱糖宝
  • 2024-09-13
  • 2049
  • 0
  • 0

首先,這個問題考察的是你對執行緒池 execute 方法和 submit 方法的理解,在 Java 執行緒池的使用中,我們可以透過 execute 方法或 submit 方法給執行緒池新增任務,但如果執行緒池中的程式在執行時,遇到了未處理的異常會怎麼呢?接下來我們一起來看。

1.execute方法

execute 方法用於提交一個不需要返回值的任務給執行緒池執行,它接收一個 Runnable 型別的引數,並且不返回任何結果。

它的使用示例程式碼如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecuteDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        // 使用 execute 方法提交任務
        executor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("Task running in " + Thread.currentThread().getName());
                try {
                    // 模擬任務執行
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.err.println("Task was interrupted");
                }
                System.out.println("Task finished");
            }
        });

        // 關閉執行緒池
        executor.shutdown();
    }
}


2.submit方法

submit 方法用於提交一個需要返回值的任務(Callable 物件),或者不需要返回值但希望獲取任務狀態的任務(Runnable 物件,但會返回一個 Future 物件)。

它接收一個 Callable 或 Runnable 型別的引數,並返回一個 Future 物件,透過該物件可以獲取任務的執行結果或檢查任務的狀態。

2.1 提交Callable任務

示例程式碼如下:

import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutionException;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  
  
public class SubmitCallableDemo {  
    public static void main(String[] args) {  
        // 建立一個固定大小的執行緒池  
        ExecutorService executorService = Executors.newFixedThreadPool(2);  
  
        // 提交一個 Callable 任務給執行緒池執行  
        Future<String> future = executorService.submit(new Callable<String>() {  
            @Override  
            public String call() throws Exception {  
                Thread.sleep(2000); // 模擬任務執行時間  
                return "Task's execution result";  
            }  
        });  
  
        try {  
            // 獲取任務的執行結果  
            String result = future.get();  
            System.out.println("Task result: " + result);  
        } catch (InterruptedException | ExecutionException e) {  
            e.printStackTrace();  
        }  
  
        // 關閉執行緒池  
        executorService.shutdown();  
    }  
}


2.2 提交Runnable任務

提交 Runnable 任務並獲取 Future 物件,示例程式碼如下:

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  
  
public class SubmitRunnableDemo {  
    public static void main(String[] args) {  
        // 建立一個固定大小的執行緒池  
        ExecutorService executorService = Executors.newFixedThreadPool(2);  
  
        // 提交一個 Runnable 任務給執行緒池執行,並獲取一個 Future 物件  
        Future<?> future = executorService.submit(new Runnable() {  
            @Override  
            public void run() {  
                System.out.println("Task is running in thread: " + Thread.currentThread().getName());  
            }  
        });  
  
        // 檢查任務是否完成(這裏只是爲了示例,實際使用中可能不需要這樣做)  
        if (future.isDone()) {  
            System.out.println("Task is done");  
        } else {  
            System.out.println("Task is not done yet");  
        }  
  
        // 關閉執行緒池  
        executorService.shutdown();  
    }  
}


3.遇到未處理異常

執行緒池遇到未處理的異常執行行為和新增任務的方法有關,也就是說 execute 方法和 submit 方法在遇到未處理的異常時執行行為是不一樣的

3.1 execute方法遇到未處理異常

示例程式碼如下:

import java.util.concurrent.*;

public class ThreadPoolExecutorExceptionTest {
    public static void main(String[] args)  {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(100));
        // 新增任務一
        executor.execute(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("執行緒名:" + tName);
            throw new RuntimeException("丟擲異常");
        });
        // 新增任務二
        executor.execute(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("執行緒名:" + tName);
            throw new RuntimeException("丟擲異常");
        });
    }
}


以上程式的執行結果如下:

Java執行緒池遇到未處理的異常會崩潰嗎?

從上述結果可以看出,執行緒池中的核心和最大執行緒數都為 1 的情況下,到遇到未處理的異常時,執行任務的執行緒卻不一樣,這說明了:當使用 execute 方法時,如果遇到未處理的異常,會丟擲未捕獲的異常,並將當前執行緒進行銷燬

3.2 submit方法遇到未處理異常

然而,當我們將執行緒池的新增任務方法換成 submit() 之後,執行結果又完全不同了,以下是示例程式碼:

import java.util.concurrent.*;

public class ThreadPoolExecutorExceptionTest {
    public static void main(String[] args)  {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(100));
        // 新增任務一
       Future<?> future = executor.submit(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("執行緒名:" + tName);
            throw new RuntimeException("丟擲異常");
        });
        // 新增任務二
        Future<?> future2 =executor.submit(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("執行緒名:" + tName);
            throw new RuntimeException("丟擲異常");
        });
        try {
            future.get();
        } catch (Exception e) {
            System.out.println("遇到異常:"+e.getMessage());
        }
        try {
            future2.get();
        } catch (Exception e) {
            System.out.println("遇到異常:"+e.getMessage());
        }
    }
}


以上程式的執行結果如下:

Java執行緒池遇到未處理的異常會崩潰嗎?

從上述結果可以看出,submit 方法遇到未處理的異常時,並將該異常封裝在 Future 的 get 方法中,而不會直接影響執行任務的執行緒,這樣執行緒就可以繼續複用了

小結

執行緒池在遇到未處理的異常時,不同新增任務的方法的執行行為是不同的:

  • execute 方法:遇到未處理的異常,執行緒會崩潰,並列印異常資訊。

  • submit 方法:遇到未處理的異常,執行緒本身不會受到影響(執行緒可以複用),只是將異常資訊封裝到返回的物件 Future 中。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.