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();
}
}
}