java 高併發 之 線程池(Executor)

爲什麼需要線程池?

(1)因爲服務器如果每一個請求都會創建一個新線程,會導致性能上的瓶頸,因爲線程創建和銷燬都需要jvm不停的處理,如果一個線程執行的時間 < (線程創建時間+線程銷燬的時間)的時候,我們就要考慮線程的複用了!

(2)、線程數量創建過多,沒有有效的管理,反而起到的是副作用,會大大降低系統的性能的!

(3)、我們要根據具體的業務需求不同,結合操作系統的處理器CPU核數,能夠合理的控制線程池大小!選擇不同策略的線程池,盲目使用也會帶來一定風險,比如內存泄漏,死鎖,併發問題…

使用線程池的好處

(1)、降低資源消耗:線程複用。

(2)、提高響應速度:有任務的時候,不需要去等待創建線程,直接使用已有的線程;

(3)、管理:線程池對線程進行統一分配,調優,監控等等;

Executor接口

Executor的UML圖:(常用的幾個接口和子類)
Executor:一個接口,其定義了一個接收Runnable對象的方法executor,其方法簽名爲executor(Runnable command),
ExecutorService:是一個比Executor使用更廣泛的子類接口,其提供了生命週期管理的方法,以及可跟蹤一個或多個異步任務執行狀況返回Future的方法
AbstractExecutorService:ExecutorService執行方法的默認實現
ScheduledExecutorService:一個可定時調度任務的接口
ScheduledThreadPoolExecutor:ScheduledExecutorService的實現,一個可定時調度任務的線程池
ThreadPoolExecutor:線程池,可以通過調用Executors以下靜態工廠方法來創建線程池並返回一個ExecutorService對象:


public ThreadPoolExecutor(int corePoolSize,  // 核心線程數,如果運行的線程少於corePoolSize,則創建新線程來執行新任務,即使線程池中的其他線程是空閒的
                          int maximumPoolSize,// 最大線程數,可允許創建的線程數,corePoolSize和maximumPoolSize設置的邊界自動調整池大小:
                          // corePoolSize <運行的線程數< maximumPoolSize:僅當隊列滿時才創建新線程
// corePoolSize=運行的線程數= maximumPoolSize:創建固定大小的線程池
                          long keepAliveTime, // 如果線程數多於corePoolSize,則這些多餘的線程的空閒時間超過keepAliveTime時將被終止
                          TimeUnit unit, // keepAliveTime參數的時間單位
                          BlockingQueue<Runnable> workQueue, // 保存任務的阻塞隊列,與線程池的大小有關:
  // 當運行的線程數少於corePoolSize時,在有新任務時直接創建新線程來執行任務而無需再進隊列
  // 當運行的線程數等於或多於corePoolSize,在有新任務添加時則選加入隊列,不直接創建線程
  // 當隊列滿時,在有新任務時就創建新線程
                          ThreadFactory threadFactory, // 使用ThreadFactory創建新線程,默認使用defaultThreadFactory創建線程
                          RejectedExecutionHandler handler) //後兩個參數爲可選參數:定義處理被拒絕任務的策略,默認使用ThreadPoolExecutor.AbortPolicy,任務被拒絕時將拋出RejectExecutorException

Executors類

Java線程池的靜態工廠類:Executors類,初始化4種類型的線程池:

newFixedThreadPool()

說明:初始化一個指定線程數的線程池,其中corePoolSize == maxiPoolSize,使用LinkedBlockingQuene作爲阻塞隊列
特點:即使當線程池沒有可執行任務時,也不會釋放線程。

		ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();

newCachedThreadPool()

說明:初始化一個可以緩存線程的線程池,默認緩存60s,線程池的線程數可達到Integer.MAX_VALUE,即2147483647,內部使用SynchronousQueue作爲阻塞隊列;
特點:在沒有任務執行時,當線程的空閒時間超過keepAliveTime,會自動釋放線程資源;當提交新任務時,如果沒有空閒線程,則創建新線程執行任務,會導致一定的系統開銷;

	ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();

因此,使用時要注意控制併發的任務數,防止因創建大量的線程導致而降低性能。

newSingleThreadExecutor()

說明:初始化只有一個線程的線程池,內部使用LinkedBlockingQueue作爲阻塞隊列。
特點:如果該線程異常結束,會重新創建一個新的線程繼續執行任務,唯一的線程可以保證所提交任務的順序執行

		ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();

newScheduledThreadPool()

特定:初始化的線程池可以在指定的時間內週期性的執行所提交的任務,在實際的業務場景中可以使用該線程池定期的同步數據。除了newScheduledThreadPool的內部實現特殊一點之外,其它線程池內部都是基於ThreadPoolExecutor類(Executor的子類)實現的。

		ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

        executorService.schedule(new Runnable() {
            @Override
            public void run() {
                log.warn("schedule run");
            }
        }, 3, TimeUnit.SECONDS);

        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.warn("schedule run");
            }
        }, 1, 3, TimeUnit.SECONDS);

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.warn("timer run");
            }
        }, new Date(), 5 * 1000);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章