線程池:異步處理 + 延遲響應

常見的線程池:

ExecutorService executor = Executors.newCachedThreadPool() ;

1、newFixedThreadPool() 創建固定大小的線程池 線程池的大小一旦達到最大值就會保持不變,如果某個線程因爲執行異常而結束,那麼線程池會補充一個新線程

2、newCachedThreadPool() 創建一個可緩存的線程池,如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閒(60s不執行任務)的線程,當任務數量增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於系統(JVM)能夠創建的最大線程大小

3、newSingleThreadExecutor() 創建一個單線程的線程池。這個線程池只有線程在工作,也就是相當於單線程串行執行所有任務。如果這個唯一的線程因爲異常結束,那麼會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行

4、newScheduledThreadPool() 創建一個大小無限的線程池,此線程池支持定時以及週期性執行任務的需求

5、newSingleThreadScheduledExecutor() 創建一個單線程的線程池。此線程池支持定時以及週期性執行任務的需求

寫一個不太完美的例子:主線程在處理比較慢的業務邏輯時,可用帶返回值的submit(Callable)或submit(Runnable, T),也可用不帶返回值的submit(Runnable),均可實現異步處理、同步響應(立即跳出主線程,不會造成阻塞延遲)的效果,不過在用帶返回值時,必須不在主線程中使用返回值Future的狀態(比如其.get()或.isDone()=true方法),否則還是會造成阻塞等待(進而導致前端超時問題,要是跟前端不用交互,則無此問題)。但問題來了,不用異步線程的Future狀態(get()或isDone()=true),怎麼知道邏輯處理完了呢?這就需要重新開啓一個線程去讀這個狀態值(期間可以把Future對象作爲參數傳給新線程去監控其isDone()或get()),當然,這個新線程可以是前端請求過來的(如以下的例子),也可以是後端websocket主動請求前端的。還有一種比較好的方案是在主線程中不使用結果值,同樣不造成阻塞等待,同樣不造成前端請求超時,但在處理邏輯時需要把任務結果Future或業務層面的結果(比如批量場景下的每條數據、或流程場景下的節點狀態數據)存到緩存或數據庫,同樣地前端頁面去重新輪訓請求獲取這些結果已達到得知處理結果的情況。

        比較一下子,第一個方案是用後臺開啓監控線程(用線程池創建線程)去監控結果狀態,這個狀態值是存儲在jvm內存裏的,所以要求狀態值裏邊的數據不是太大,且機器一掛掉或停電,會造成這些所有的內存裏的數據都會消失,所以要求任務數據的安全度不是太高(比如一些爬蟲任務或定時任務啥的,就算掛掉後重新開啓任務可以繼續跑),但其優點是不用前後端頻繁創建鏈接,且由於是線程池在維護監控線程,不用頻繁創建銷燬線程,且不存在存庫問題,也省去了連接庫的那一套消耗。第二個方案的特點是跟上邊對立的,安全級別高(因爲有狀態持久化),但頻繁調度時可能會犧牲點時間性能,但jvm的內存壓力不會太大。總之,還是老生常談的“犧牲時間換取空間性能,犧牲空間換取時間性能”問題。


public class ThreadPoolTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService e = Executors.newFixedThreadPool(5);
        long l = System.currentTimeMillis();
        final Future<Integer> s = e.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("執行長邏輯線程:" + Thread.currentThread().getName());
                Thread.sleep(5000);
                return 0;
            }
        });
        System.out.println("主線程:" + Thread.currentThread().getName() + "開始任務~結束任務需要毫秒:" + (System.currentTimeMillis() - l));

        e.submit(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                long q = System.currentTimeMillis();
                while (true) {
                    if (s.isDone()) {
                        try {
                            System.out.println("監控狀態線程:" + Thread.currentThread().getName() + ",慢邏輯執行完畢結果:" + s.get());
                        } catch (InterruptedException e1) {
                            e1.printStackTrace();
                        } catch (ExecutionException e1) {
                            e1.printStackTrace();
                        }
                        break;
                    }
                }
                System.out.println("監控狀態線程:" + Thread.currentThread().getName() + ",耗時毫秒數" + (System.currentTimeMillis() - q));
                return null;
            }
        });
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章