線程池原理你知道多少?

程序員成長路上有着不同的階段,只要你翻過了當時那個階段,那麼你將會有了不一樣的收穫。很多時候,我們在剛開始面對它們的時候,還看不清,看不透,雲裏霧裏,讓人覺得它們很高深。等我們正在的瞭解它們了之後就覺一切都是那麼簡單、自然。

 

再努力一下,一切將會不一樣!—— 魯迅

前言

多線程開發就是這樣的一座山,需要我們去克服。說到多線程,大部分新手(作者自己),在面試中談到多線程就慌了,因爲自己在實際工作中真的很少碰到,而且我們多數時候都是在做傳統的單體項目開發,說真的,很少會碰到用到多線程的,用都沒用過面試的時候讓我們怎麼說。爲了讓大家對多線程有個大致瞭解,現在讓作者我跟大家瞎扯幾句,作者很少寫文章,寫得不太通順的地方,大家多(wang)多(si)諒(li)解(pen) 。

 

既然要講多線程,就不得不說下線程、線程池了~

 

 

線程

在Java中你會怎麼創建一個線程嗎?

很簡單啊,比如說:

Thread t = new Thread(new Runnable() {
           @Override
           public void run() {
              // 處理邏輯代碼
              process();
          }
      });
t.start();

恩,沒錯,這樣確實可以簡單的創建出一個線程對象。

我們知道一個線程的創建於銷燬是需要消耗資源的,大家來思考一個問題:假設我們項目中要經常用到多個線程去處理業務的話,每次都是用完就銷燬,這也未免太浪費了些吧,畢竟線程只是幫我們執行相應的任務,完全可以繼續複用它呀,讓它接着處理其他任務。那麼在Java中有沒有一種辦法使得線程可以複用,就是執行完一個任務,並不被銷燬,而是可以繼續執行其他的任務?

如果之前大家有看過《阿里巴巴 Java 手冊》的話,那麼應該知道有那麼一條:

可見線程池就是我們的答案!

線程池的作用

簡單來說使用線程池有以下幾個目的:

  • 線程是稀缺資源,不能頻繁的創建。

  • 解耦作用,線程的創建於執行完全分開,方便維護。

  • 應當將其放入一個池子中,可以給其他任務進行復用。

線程池原理

簡單來說就是把寶貴的資源管理起來,每次用的時候再去取,用完放回,讓其他人也可以複用。

那在Java中我們該怎麼實現呢?

在Java中線程池的核心類是ThreadPoolExecutor,並在此類的基礎上封裝了幾種常用線程池:

  • Executors.newCachedThreadPool():無限線程池。

  • Executors.newFixedThreadPool(nThreads):創建固定大小的線程池。

  • Executors.newSingleThreadExecutor():創建單個線程的線程池。

我們看下他們是怎麼實現的:

// 無限線程池
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
   return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                 60L, TimeUnit.SECONDS,
                                 new SynchronousQueue<Runnable>(),
                                 threadFactory);
}
// 創建固定大小的線程池
public static ExecutorService newFixedThreadPool(int nThreads) {
       return new ThreadPoolExecutor(nThreads, nThreads,
                                     0L, TimeUnit.MILLISECONDS,
                                     new LinkedBlockingQueue<Runnable>());
}
// 創建單個線程的線程池
public static ExecutorService newSingleThreadExecutor() {
       return new FinalizableDelegatedExecutorService
          (new ThreadPoolExecutor(1, 1,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>()));
}

看上面源代碼,我們知道它們都是基於ThreadPoolExecutor 實現的,那我們就來看看它們是給ThreadPoolExecutor傳了什麼參數才導致它們可以實現不同功能的線程池的呢?

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

由上面的參數解釋,我們可以知道,線程池是通過設置corePoolSize(最小線程數)和maximumPoolSize(最大線程數)來確定線程池的大小範圍,讓線程池在我們定義範圍內擴容、減容。線程池的擴容是要判斷當前所需的線程數是否超過核心線程數阻塞隊列也滿了並且當前線程數小於最大線程數,都符合了,纔會擴容。我們可以看下面的流程圖來理解:

  • corePoolSize 核心線程數,爲線程池的基本大小。

  • maximumPoolSize 爲線程池最大線程大小。

  • keepAliveTimeunit 則是線程空閒後的存活時間。

  • workQueue 用於存放任務的阻塞隊列。

  • threadFactory 線程工廠,主要用來創建線程。

  • handler 當隊列和最大線程池都滿了之後的飽和策略。

    • ThreadPoolExecutor.AbortPolicy 丟棄任務並拋出RejectedExecutionException異常

    • ThreadPoolExecutor.DiscardPolicy 也是丟棄任務,但是不拋出異常

    • ThreadPoolExecutor.DiscardOldestPolicy 丟棄隊列最前面的任務,然後重新嘗試執行任務(重複此過程)

    • ThreadPoolExecutor.CallerRunsPolicy 由調用線程處理該任務

 

 

雖然,Executors給我們封裝好了上面幾個構建線程池的方法,但是,並不建議直接使用

爲什麼呢?

讓我們來看看阿里巴巴的開發手冊:

讓我們看下源碼是不是真的這樣:

  • Executors 源碼

// Executors.class
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                      0L, TimeUnit.MILLISECONDS,
                      new LinkedBlockingQueue<Runnable>()));// 這裏採用了無參構造方法
}
  • LinkedBlockingQueue源碼

// LinkedBlockingQueue.class
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);  // 無參構造方法,直接設置爲Integer.MAX_VALUE大小
}
public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
    last = head = new Node<E>(null);
}

果然如此~

所以還是按照我們自己業務上需求自定義配置屬於自己的線程池吧!

好了,暫時先講到這啦~

大家覺得不錯幫忙點個在看哈~

 

參考:

https://blog.csdn.net/pange1991/article/details/53860651

《阿里巴巴Java開發手冊》

 

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