圖解定時任務線程池

線程池概念


咱們上篇文章分析了ThreadPoolExecutor,若是要用一句話說明它的主要優點,就是線程置換。還有Executors工具類,極大的簡化了研發人員工做。java

我用一個圖重複描述下線程池概念。多生產-多消費模型。面試

image.png


  • 生產者將線程任務丟進線程池中,生產者就就結束了。
  • 線程池控制消費者消費元素,消費者能夠是1個或者多個,取決於線程池參數corePoolSize和maxPoolSize設置。
  • 阻塞隊列是用來裝生產者丟進去的線程任務,如ArrayBlockingQueue,LinkedBlockingQueue,DelayedQueue等。若是生產者生產能力超過消費者消費能力,若是阻塞隊列有長度限制而且超過隊列長度線程池會執行飽和策略,若是隊列沒有長度限制,可也能出現OOM哦,由於線程任務可能把內存都撐爆了,這也是面試常考點哦!

詳細概念能夠翻看我上一篇文章《線程池面試必考問題》。微信



定時任務延時原理


還記得咱們上面說的阻塞隊列嗎?定時任務線程池底層使用DelayedQueue實現的,這種延遲隊列有一個最大的特色:按時出隊列,你們都考過駕照吧,科目三考試的時候都是車上坐的是4我的,假設一我的考試須要花15分鐘,那麼考試學員隊列看起來是這樣的。多線程

image.png

DelayedQueue底層須要實現Delayed接口同時須要實現getDelay方法和compareTo方法,getDelay方法用於計算出隊列時間,一旦小於0就會出隊列;compareTo方法用於按觸發時間從小到大排序。這就是Schedule線程池任務延時原理,若是須要看案例代碼,請參考我文章《併發隊列:PriorityBlockingQueue和DelayQueue案例使用》。併發


scheduleWithFixedDelay和scheduleAtFixedRate區別


image.png

由上圖可知:假設線程任務:耗時1秒,定時3秒執行,scheduleWithFixedDelay實際上是4秒執行一次。ide

  • scheduleWithFixedDelay:是以任務結束時間週期運行。
  • scheduleAtFixedRate:是以固定週期運行。



FutureTask獲取返回值


在ScheduledThreadPoolExecutor中,ScheduledFutureTask是獲取定時任務返回值,繼承FutureTask。咱們看下FutureTask調用get阻塞簡化流程圖。工具

image.png

  1. 向線程池添加任務,任務被封裝成ScheduledFutureTask而且實現Callable接口是爲了獲取任務返回值。
  2. 當客戶端線程經過get方式獲取線程池線程執行的返回值,客戶端線程會阻塞直到線程池線程任務執行完。

在實際運用,咱們通常拿返回值測試多線程性能。性能



Timer比較


  1. Timer是單線程,並且不帶返回值。ScheduledThreadPoolExecutor是多線程的,採用線程複用代替建立新的線程,而且FutureTask返回值。
  2. Timer線程調用sche方法,若是TimerTask出異常,Timer單線程直接掛掉退出,而ScheduledThreadPoolExecutor會捕獲了異常,不影響其餘消費者線程。下面是代碼測試。
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

/**
 * @author :jiaolian
 * @date :Created in 2021-02-25 13:50
 * @description:Timer任務異常,Timer線程退出!
 * @modified By:
 * 公衆號:叫練
 */
public class TimerTaskExceptionTest {

    public static void main(String[] args) throws InterruptedException {

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("first task");
            }
        },0,1000);

        TimeUnit.SECONDS.sleep(3);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("second task");
                int x = 5/0;
            }
        },0,1000);

    }
}

如上代碼:timer提交了first_task和second_task兩個任務,3秒後,second_task執行5/0會拋出異常,此時timer線程會退出。若是換成ScheduledThreadPoolExecutor則不會影響first_task。在實際應用中,推薦用定時任務線程池中的方法去處理任務。測試


總結


今天咱們介紹了線程池中面試中幾個重要的面試點,整理出來但願能對你有幫助,寫的比不全,同時還有許多須要修正的地方,但願親們加以指正和點評,喜歡的請點贊加關注哦。點關注,不迷路,我是叫練【公衆號】,微信號【jiaolian123abc】邊叫邊練。spa

相關文章
相關標籤/搜索