1. 程式人生 > >Java生產環境執行緒池使用場景

Java生產環境執行緒池使用場景

talk is cheap, show me the code 直接上程式碼

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author by bixi.lx
 * @created on 2018 07 28 22:17
 */
public class ThreadPoolProduction {

    public static void main(String[] args) {

        BussinessService bussinessService = new BussinessServiceImpl();

        //新建一個執行緒池,池中有兩個執行緒,注意這裡使用的是fiexd 注意和cached的區別
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        //注意這裡使用的是callable 而不是runable。
        ArrayList<Callable<Integer>> tasks = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            tasks.add(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    bussinessService.handleBussiness();
                    return 0;
                }
            });
        }

        try {
            //由於我們使用的是callable,所以在執行完成後,會拿到反饋資訊,而runable不可以
            List<Future<Integer>> futures = executorService.invokeAll(tasks);
            for (Future<Integer> future : futures) {
                System.out.println(future.get());
            }
        } catch (ExecutionException e) {
            //這裡生產環境不可以這麼寫,不要生吞(swallow)異常,處理的方式有很多種,比如可以向日志系統追加日誌
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

首先,新建了一個執行緒池,注意這個執行緒池是fixed的(執行緒池建立主要由四種方式,具體哪四種,我還真不記得了,阿里的面試問到了, 印象非常深的記住了兩種,就是fixed和cached,當時回答了這兩個的區別,並且講了下fixed的缺點,後面我們會深入講解這個。)

其次,我們新建了一個任務的列表tasks(注意這個列表的泛型是callable)

最後,我們提交批量執行這個任務,由於執行緒池中只有兩個執行緒,所以會看見每次都是打印出兩行。(執行這裡是最關鍵的,因為之前我們的任務都是基於callable的,所以執行之後會返回一個future,future大家都熟悉了,專案中也有使用到,使用的場景就是處理完成之後會返回一個回執內容。)

專案中要看具體的業務場景了,由於報表專案是使用mysql來使用資料庫的資源進行計算的,根據生產環境的伺服器和rds mysql資料的連線資源,所以最適合不過使用fixed的執行緒池了,報表,計算資料的時候,出錯了就出錯了,大不了重新算,所以現在的生產環境中,拿到callable執行後的結果也並沒有做任何的處理。這裡就有人會問了,如果真的出錯了怎麼辦,又沒有拿到錯誤的資訊,都不會知道是不是出現了錯誤,實際上如果報表在計算任務中出現了失敗,那麼會在具體的業務程式碼中,記錄失敗的日誌資訊到es,顯示在kibana中。當然,實際上,就算是沒有記錄錯誤資訊,出現了錯誤沒被發現,也不會有太大的問題。很多時候,恰巧不解決,反而降低了實現的複雜度,因為在報表的業務實現上,做了一些設計,哪怕是出錯了,也沒關係的。至於這些設計是哪些,後面我會找時間整理出來。

下圖是程式執行過程中,執行緒的使用情況,可以看到pool-1 執行緒池中有2 similar threads, 分別是pool-1-thread-2 pool-1-thread-1兩個執行緒當前沒有要處理的任務,處於等待狀態

/**
 * @author by bixi.lx
 * @created on 2018 07 28 22:51
 */
public interface BussinessService {

    void handleBussiness();
}
/**
 * @author by bixi.lx
 * @created on 2018 07 28 22:52
 */
public class BussinessServiceImpl implements BussinessService {

    @Override
    public void handleBussiness() {
        System.out.println("處理業務邏輯");

        // 為了觀察執行緒是根據執行緒池設定的執行緒數,批量執行的,這裡加上執行緒休眠
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}