面試官這樣問Java 線程池,我的回答讓他豎起了大拇指!

前言

這周我投遞出了簡歷,崗位是java後端開發工程師。這周美團面試官給我進行了面試。面試過程中他問了線程池,今天詳細講一講Java 線程池

線程池

線程池維護着多個線程,等待着監督管理者分配可併發執行的任務。這避免了在處理短時間任務時創建與銷燬線程的代價。

start()創建一定數量的線程池,進行線程循環

stop()停止所有線程循環,回收所有資源

addTask()添加任務

Excutors創建線程池便捷方法如下:

Executors.newFixedThreadPool(100);//創建固定大小的線程池
Executors.newSingleThreadExecutor();//創建只有一個線程的線程池
Executors.newCachedThreadPool();//創建一個不限線程數上限的線程池,任何提交的任務都將立即執行

對於服務端需要長期運行的程序,創建線程池應該使用ThreadPoolExecutor的構造方法

public ThreadPoolExecutor(
      int corePoolPoolSize,//線程池長期維持的線程數
      int maximumPoolSize, //線程數的上限
      long keepAliveTime,//空閒線程存活時間
      TimeUnit unit,//時間單位
      BlockingQueue<Runnable> workQueue,//任務的排隊隊列
      ThreadFactory threadFactory,//新線程的產生方式
      RejectedExecutionHandler handler//拒絕策略
  )

java線程池有7大參數,4大特性。

特性一:當池中正在運行的線程數(包括空閒線程)小於corePoolSize時,新建線程執行任務。

特性二:當池中正在運行的線程數大於等於corePoolSize時,新插入的任務進入workQueue排隊(如果workQueue長度允許),等待空閒線程來執行。

特性三:當隊列裏的任務數達到上限,並且池中正在運行的線程數小於maximumPoolSize,對於新加入的任務,新建線程。

特性四:當隊列裏的任務數達到上限,並且池中正在運行的線程數等於maximumPoolSize,對於新加入的任務,執行拒絕策略(線程池默認的拒絕策略是拋異常)。

種類

newCachedThreadPool

  • 核心線程數爲0,最大線程數爲 Integer.MAX_VALUE
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

作用

創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們,並在需要時使用提供的 ThreadFactory 創建新線程。

特徵

(1)線程池中數量沒有固定,可達到最大值(Interger. MAX_VALUE)
(2)線程池中的線程可進行緩存重複利用和回收(回收默認時間爲1分鐘)
(3)當線程池中,沒有可用線程,會重新創建一個線程

創建方式

Executors.newCachedThreadPool();

newFixedThreadPool

  • 核心線程數與最大線程數均爲指定的nThreads

  • 空閒線程的存活時間是0

  • 工作隊列是無界隊列

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

作用

創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。在任意點,在大多數 nThreads 線程會處於處理任務的活動狀態。如果在所有線程處於活動狀態時提交附加任務,則在有可用線程之前,附加任務將在隊列中等待。如果在關閉前的執行期間由於失敗而導致任何線程終止,那麼一個新線程將代替它執行後續的任務(如果需要)。在某個線程被顯式地關閉之前,池中的線程將一直存在。

特徵

(1)線程池中的線程處於一定的量,可以很好的控制線程的併發量
(2)線程可以重複被使用,在顯示關閉之前,都將一直存在
(3)超出一定量的線程被提交時候需在隊列中等待

創建方式

1)Executors.newFixedThreadPool(int nThreads)//nThreads爲線程的數量 2)Executors.newFixedThreadPool(int nThreads,ThreadFactory threadFactory)//nThreads爲線程的數量,threadFactory創建線程的工廠方式

newSingleThreadExecutor

  • 核心線程數與最大線程數均爲1
  • 工作隊列是無界隊列
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

作用

創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。(注意,如果因爲在關閉前的執行期間出現失敗而終止了此單個線程,那麼如果需要,一個新線程將代替它執行後續的任務)。可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的。與其他等效的 newFixedThreadPool(1) 不同,可保證無需重新配置此方法所返回的執行程序即可使用其他的線程。

特徵

線程池中最多執行1個線程,之後提交的線程活動將會排在隊列中以此執行。

創建方式

1)Executors.newSingleThreadExecutor() ; 
(2)Executors.newSingleThreadExecutor(ThreadFactory threadFactory)// threadFactory創建線程的工廠方式

newScheduledThreadPool

  • 指定核心線程數corePoolSize
  • 最大線程數是Integer.MAX_VALUE
  • DelayedWorkQueue:任務隊列會根據任務延時時間的優先級進行執行
public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService {
        ....................
	/**
     * Creates a new {@code ScheduledThreadPoolExecutor} with the
     * given core pool size.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     */
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    .......................
}

作用

創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行

特徵

(1)線程池中具有指定數量的線程,即便是空線程也將保留
(2)可定時或者延遲執行線程活動

創建方式

1)Executors.newScheduledThreadPool(int corePoolSize)// corePoolSize線程的個數 2newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)// corePoolSize線程的個數,threadFactory創建線程的工廠

newSingleThreadScheduledExecutor

作用

創建一個單線程執行程序,它可安排在給定延遲後運行命令或者定期地執行。

特徵

(1)線程池中最多執行1個線程,之後提交的線程活動將會排在隊列中以此執行
(2)可定時或者延遲執行線程活動

創建方式

1)Executors.newSingleThreadScheduledExecutor() ; 
(2)Executors.newSingleThreadScheduledExecutor(ThreadFactory threadFactory)//threadFactory創建線程的工廠

工作隊列

SynchronousQueue:直接提交

是工作隊列的默認選項,將任務直接提交給線程而不保持。

如果不存在可用於立即運行任務的線程,則試圖把任務加入隊列將失敗,因此會構造一個新的線程。

優缺點

優點:可以避免在處理可能具有內部依賴性的請求集時出現鎖。

直接提交通常要求無界maximumPoolSizes 以避免拒絕新提交的任務。

當命令以超過隊列所能處理的平均數連續到達時,此策略允許無界線程具有增長的可能性。

ArrayBlockingQueue:有界隊列

當與有限的maximumPoolSizes一起使用時,有界隊列有助於防止資源耗盡,但是調整和控制起來會更加困難。

隊列大小和最大池大小可以相互權衡

  • 使用大隊列和小池可以最大程度地減少CPU使用率,操作系統資源和上下文切換開銷,但可能導致人爲地降低吞吐量

  • 如果任務頻繁阻塞(例如如果它們是受I/O約束的),則系統可能可以爲非預定的更多線程安排時間。

  • 使用小隊列通常需要更大的池大小,這會使CPU繁忙,但可能會遇到不可接受的調度開銷,這也會降低吞吐量

LinkedBlockingQueue:無界隊列

在所有核心線程都忙時,新任務在隊列中等待。
因此,僅創建corePoolSize線程即可。(maximumPoolSize的值沒有任何作用。)
當每個任務完全獨立於其他任務時,因此任務不會影響彼此的執行。

優缺點

優點:例如,在網頁服務器中,儘管這種排隊方式對於消除短暫的突發請求很有用。
缺點:當命令請求到達速度比其處理速度更快時,工作隊列無限制增長。

拒絕策略

AbortPolicy:處理程序遭到拒絕將拋出運行時 RejectedExecutionException

DiscardPolicy:不能執行的任務將被刪除

DiscardOldestPolicy:如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程序(如果再次失敗,則重複此過程)

CallerRunsPolicy:線程調用運行該任務的 execute 本身。此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度。

RejectedExecutionHandler rejected = null;

rejected = new ThreadPoolExecutor.AbortPolicy();//默認,隊列滿了丟任務拋出異常

rejected = new ThreadPoolExecutor.DiscardPolicy();//隊列滿了丟任務不異常

rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//將最早進入隊列的任務刪,之後再嘗試加入隊列

rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到線程池失敗,那麼主線程會自己去執行該任務

參考鏈接:https://www.cnblogs.com/cdf-opensource-007/p/8769777.html
參考鏈接:https://www.cnblogs.com/vince66/p/9325638.html
參考鏈接:http://www.mamicode.com/info-detail-2740441.html

總結

咱們玩歸玩,鬧歸鬧,別拿面試開玩笑。

線程池記憶口訣:七個參數,四大特性,五個種類、三大工作隊列、四大拒絕策略

線程池,在面試中出現的次數非常多,大家面試前要把知識點記牢。

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