java多線程(複習-10)線程池1

前言

1,線程池就是爲了避免系統頻繁的創建和銷燬線程,就像數據庫連接池類似。

2,jdk 已經提供了對線程值的支持。那就是Exeutor框架

一,Java線程池提供的幾種工廠方法

static ExecutorService newCachedThreadPool() 
          創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。
static ExecutorService newFixedThreadPool(int nThreads) 
          創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 
          創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行。
static ExecutorService newSingleThreadExecutor() 
          創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。
static ScheduledExecutorService newSingleThreadScheduledExecutor() 
          創建一個單線程執行程序,它可安排在給定延遲後運行命令或者定期地執行。

區別:

1,第一個工程返回一個可根據實際情況調整線程熟練的線程池,當線程有空閒的,新的任務添加時,就會複用線程,如果沒有空閒線程,那麼就會創建新的線程處理任務,如果任務過多,那麼就會導致OOM。

內部實現:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

2,第二個方法返回一個固定大小的線程池,也就是說線程持中的線程數保持不變,當又新的任務添加時,如果沒有線程可供複用,就會把這個任務添加到任務隊列,

內部實現:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

3,第三個方法返回一個ScheduleExecutorService對象 ,這個線程池是按照一定週期去執行任務的。

public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

4,第四個返回一個只有一個線程的線程池,多餘的任務會被提交到任務隊列。

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

5,第五個和第三個類似。但線程大小隻有一個

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

可以看出:除了創建有計劃時間的線程池,其他的內部都是使用了

public ThreadPoolExecutor(int corePoolSize,//指定線程池中線程的數量
                              int maximumPoolSize,//制定線程池中最大的線程數量
                              long keepAliveTime,//多餘線程的存活時間
                              TimeUnit unit,//存活時間的單位
                              BlockingQueue<Runnable> workQueue,//違背執行的任務隊列
                              ThreadFactory threadFactory,//線程工廠
                              RejectedExecutionHandler handler)//拒絕策略  
                              )

這個構造方法的關鍵參數就是阻塞隊列的不同實現,從而導致不同線程池的不同功能,以及使用技巧。

二,阻塞隊列的區別:

1,直接提交隊列,SynchronousQueue,該隊列沒有容量,每一個插入操作都會等待一個刪除操作。提交的任務不會被真實的保存,總是新的任務 提交個線程執行,沒有空閒,就會創建新的線程,那麼使用該隊列所創的線程池,當進程數量達到最大值,就會採取拒絕策略,若不想這樣的情況,就要設置很大的線程數,那麼就會導致OOM。

2,有界的任務隊列,ArrayBlockingQueue,使用該隊列創建的線程池,判斷規則如下:

  

3,無界的任務隊列:LinkedBlockingQueue,相比於有界,如果實際線程數到達了corepoolSize,還有新的任務提交,就會被添加到隊列中,直到系統資源耗盡,,該方法可能會導致OOM,

4,優先級隊列,PriorityBlockingQueue,根據任務自身的優先級順序先後執行。

所以在創建線程池的時候,儘量不要直接使用Executors的工廠方法,而是使用ExecutorPoolService()的構造方法,根據需求定製參數,這樣使用線程池,更爲直觀。

 ExecutorService executorService = new ThreadPoolExecutor(5,5,0L, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>(),new RejectedExecutionHandler());

 

參考《Java高併發程序設計》

 

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