首頁 >Java >java教程 >Java實例詳解之子執行緒任務異常,主執行緒事務回滾

Java實例詳解之子執行緒任務異常,主執行緒事務回滾

WBOY
WBOY轉載
2022-05-09 17:49:493533瀏覽

本篇文章為大家帶來了關於java的相關知識,其中主要介紹了關於子執行緒任務發生異常時,主執行緒事務如何回滾的相關問題,包括了異常的捕獲和事務的回滾等內容,下面一起來看一下,希望對大家有幫助。

Java實例詳解之子執行緒任務異常,主執行緒事務回滾

推薦學習:《java影片教學

一、提出問題


##主執行緒向執行緒池提交了一個任務,如果執行這個任務過程中發生了異常,如何讓主執行緒捕獲到該異常並且進行交易的回滾

    二、主執行緒與子執行緒
  • 先來看看基礎,下圖體現了兩種執行緒的運作方式,

左側的圖,體現了主執行緒啟動一個子執行緒之後,二者互不干擾獨立運行,生死有命,從此你我是路人! Java實例詳解之子執行緒任務異常,主執行緒事務回滾

右邊的圖,體現了主執行緒啟動一個子執行緒之後繼續執行主執行緒程式邏輯,在某一節點透過阻塞的方式來取得子執行緒的執行結果。

對於上文中提出的問題,一定是第二種才能解決主執行緒能夠捕捉子執行緒執行過程中發生的例外狀況。這裡就得提一個面試題,實作執行緒的兩個介面Callable與Runnable的差別:

public interface Callable<v> {
    V call() throws Exception;}</v>
public interface Runnable {
    public abstract void run();}

可以看到call方法帶回傳值,run方法沒有回傳值。另外call方法可以拋出異常,run方法不可以。很明顯,我們為了要捕捉或得知子執行緒的運行結果,或者運行異常,都應該透過Callable介面來實現。

這裡我們寫一個ExpSubThread類別(子執行緒異常模擬類別),實作Callable接口,不做過多的動作,直接拋出一個空指標例外。
    public class ExpSubThread implements Callable {
        @Override
        public Object call() throws Exception {
            throw new NullPointerException();
        }}
  • 三、執行緒池
  • 在面對執行緒任務時,通常我們會預先建立一個執行緒池,執行緒池是預先規劃好的n個執行緒資源的集合。它的好處在於:
  • 執行任務時,不是新建一個線程,而是使用線程池內已有的線程資源。任務執行完成也不是銷毀線程,而是將線程資源歸還給線程池。所以在某種程度上,節省了執行緒創建和銷毀所消耗的資源,達到執行緒資源重複利用的目的。

    因為線程池創建的大小是有上限的,所以線程池還有另外的一個作用就是避免線程無限制的被創建,避免應用資源無限制的被佔用導致的系統宕掉的問題。

    常用的執行緒池有兩種,一種是JDK自帶的,一種是Spring執行緒池,在Spring環境下後者常常被使用,二者大同小異。這裡我們使用Spring API來建立一個線程池。

    public ThreadPoolTaskExecutor getThreadPool(){
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setMaxPoolSize(100);  //线程池最大线程数
            executor.setCorePoolSize(50);//线程池核心线程数
            executor.setQueueCapacity(50);//任务队列的大小
            executor.setThreadNamePrefix("test_"); //线程前缀名
            executor.initialize(); //线程初始化
            return executor;}
    四、異常的捕獲
    • 下面是我寫的一個測試案例,在這裡它代表了主執行緒的程式執行流程
    @Testvoid subThreadExceptionTest() {
            try{
                //新建子线程对象
                ExpSubThread expSubThread = new ExpSubThread();
                //构建线程池
                ThreadPoolTaskExecutor executor = getThreadPool();
                //提交子线程任务,submit方法
                Future future = executor.submit(expSubThread);
                //在这里可以做主线程的业务其他流程操作
                //阻塞等待子线程的执行结果
                Object obj = future.get();  
            }catch (Exception e){
                e.printStackTrace();
                //事务回滚
            }}
  • 這裡需要注意的是使用submit方法提交子執行緒任務到執行緒池內執行。 ThreadPoolTask​​Executor有兩種執行緒任務的方法,一種是execute方法,一種是submit方法。
  • execute方法沒有回傳值,所以無法判斷任務是否成功完成,對應的執行緒類別實作Runnable介面。 Java實例詳解之子執行緒任務異常,主執行緒事務回滾

    submit方法有回傳值,回傳一個Future,對應的執行緒類別實作Callable介面。

    Future.get()方法達到了阻塞主執行緒的目的,從而可以判斷子執行緒任務的執行結果,並且get方法可以拋出例外。

        V get() throws InterruptedException, ExecutionException;
    Java實例詳解之子執行緒任務異常,主執行緒事務回滾下面這張圖是上面的測試案例程式程式e.printStackTrace();

    的效果,從圖中可以看到兩個Exception例外,一個是我們在子執行緒任務中以模擬的方式主動拋出的空指標異常,另一個由於空指標引發的get方法拋出的ExecutionException。

    • 五、事務的回滾
    • 上文大家已經看到我們透過
    • 執行緒類別實作Callable接口,達到了獲取線程回傳值,或是異常拋出的目的。

    submit可以提交執行緒任務到執行緒池,並且可以取得子執行緒執行結果的回傳值Future。

    ###Future的get()方法可以取得子執行緒執行訊息,包括異常的拋出。 #########那麼既然我們已經可以在主執行緒內感知或catch子執行緒的例外訊息了,那麼下一步主執行緒的事務回滾是不是就太簡單了? ###
    • jdbc 就conn.rollback()實作交易的回溯
    • spring環境下使用@Transactional註解就可以了。

    推薦學習:《java影片教學

    以上是Java實例詳解之子執行緒任務異常,主執行緒事務回滾的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除