線程池系列二

善治病者,必醫其受病之處;
善救弊者,必塞其弊之源

書接上文線程池的設計思路,帶着如何設計拒絕策略的你,又回顧了整個流程,突然你想這事因排隊而起,能不能在排隊的隊列上有所改進。

第一部分 排隊也是值得考慮的

BlockingQueue:任務隊列
我們來看一下Doug Lea事先給我們設計好的隊列:

1. LinkedBlockingQueue

基於鏈表實現的(無界的)阻塞隊列,默認情況下容量是 Integer.MAX_VALUE,可以說是無界的。
只有調用這個構造函數纔可以設置容量capacity,否則都是Integer.MAX_VALUE。

 public LinkedBlockingQueue(int capacity) {
       if (capacity <= 0) throw new IllegalArgumentException();
       this.capacity = capacity;
       last = head = new Node<E>(null);
   }
2. ArrayBlockingQueue

基於數組實現的有界阻塞隊列。默認情況下,不保證FIFO的順序(By default, this ordering is not guaranteed).。因爲公平策略將會降低吞吐率,但是也降低了可變性以及避免了飢餓現象.(Fairness generally decreases throughput but reduces variability and avoids starvation.)

// 注意: 參數fair默認爲false,  true -保證FIFO 
 public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
3. SynchronousQueue

A blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa(反之亦然).
同步隊列-不存儲任務的阻塞隊列。插入操作 和 刪除操作是一一對應的。就像一個空集合(acts as an empty collection)

三者之間的聯繫

  1. 吞吐率角度:

SynchronousQueue > LinkedBlockingQueue > ArrayBlockingQueue

  1. FIFO的角度:

LinkedBlockingQueue 直接按照隊列的FIFO設計;
SynchronousQueue, ArrayBlockingQueue 默認都是不保證FIFO順序的,可以在構造函數中打開fairness。

  1. 容量角度:

LinkedBlockingQueue默認容量是無限制的,直接打翻了“臨時工”的飯碗。即:maxiumPoolSize失去了意義。PS:2333, "正式工"已經哭暈倒廁所裏啦,往死裏幹。

世界本來就是不公平的,面對現實吧!!!

4. PriorityBlockingQueue

具有優先級的阻塞隊列,初始容量是11。Obviously, 它不保證FIFO,如果需要可以自定義類去打破其優先級(有病啊?OR閒得啦?).

還有幾種阻塞隊列,但是我認爲記住這四種差不多就夠用啦,後面的遇到再介紹。怕:消化不良 2333

BlockingQueue歸納一下:

盡情地發揮想象:

  1. LinkedBlockingQueue:爲了防止插隊,用繩索把每個人都串聯起來(PS:這繩索默認還是無限長地(Integer.MAX_VALUE)),MMP,還得請城管大隊長喝酒啊;
  2. ArrayBlockingQueue:綁起來貌似有點不厚道,還是把繩索解開,但是都別亂動啊。爲了不驚動城管,不準站太多人。
  3. PriorityBlockingQueue:城管大人站在隊列地尾部,對你投來迷之微笑,嚇得你毛骨悚然,怕遇到“同志”。正在發愣地時候,城管大人一隻手搭在你的肩膀上,老弟不請我吃一頓。此時你那還管什麼FIFO啊,直接拉着城管大人地手往店裏走。
  4. SynchronousQueue:城管大人說飽喝足,走出門口說:上面檢查,排隊影響市容市貌,不準排隊。你看着辦吧。只能(來一個走一個,走一個來一個)。PS:一首涼涼送給你

第二部分:學會拒絕

RejectedExecutionHandler 拒絕策略

1. AbortPolicy

簡單粗暴,你值得選擇。

默認策略:直接拒絕並拋出運行時異常:RejectedExecutionException

2. DiscardPolicy

衝動是魔鬼,默默地拒絕。

直接拒絕但不拋異常。

3. DiscardOldestPolicy

爲了大局而犧牲局部利益

直接拒絕隊列的頭部,爲了不犯衆怒,你只好對隊列的第一個人說不。畢竟:得罪一個,取悅一羣啊。

4. CallerRunsPolicy

從哪來回哪去

交給調用者所在的線程來處理任務。

5. 自定義策略

隨心所欲

實現RejectedExecutionHandler接口。比如送個優惠券啥的…

RejectedExecutionExecutor總結

這裏假設:正是飢餓的時候,不讓吃飯誰能心裏舒服,誰也不願意啊,

  1. AboryPolicy :直接拒絕結果把人給打了一頓,這樣飯店也幹不下去啦…
  2. DiscardPolicy:陪着笑臉,打不還手罵不還口直的拒絕
  3. DiscardOldestPolicy: 爲了大部分人的利益而犧牲少數人。排隊的人在後面起鬨,質問前面的人怎麼還沒走啊。爲了平復後面的人,只能犧牲一下隊列首位啦。PS:電車悖論
  4. CallerRunsPolicy : 冷處理
  5. 自定義策略:爲了不得罪顧客,可能你要發個優惠券啥的。

通過這兩篇文章,我認爲大家對ThreadPoolExecutor應該有了一個清晰的認識。更爲詳細的內容,後續慢慢補充。接下來要實現你做大老闆的夢想——開連鎖店。

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