帶着新人學springboot的應用09(springboot+異步任務)

  原本想說說檢索的,不過不知道什麼鬼,下載ElasticSearch太慢了,仍是放一下,後面有機會再補上!今天就說個簡單的東西,來講說任務。java

  什麼叫作任務呢?其實就是類中實現了一個什麼功能的方法。常見的任務就是異步任務,定時任務,發郵件。web

  異步任務:其實就是一個很特別的方法,這個方法沒有返回值(也能夠有返回值,後面會說的),可是方法內部的邏輯會耗費不少時間!例如,用戶請求每次到controller,要執行到這個異步方法的時候,咱們只須要命令一個空閒狀態的線程去執行它便可,因爲沒有返回值不影響後續代碼的運行,controller直接去執行後續的代碼。這樣能夠極爲迅速的響應用戶,用戶體驗很是好。spring

  定時任務:這個其實看名字就知道了,你能夠選定一個月的哪一天哪一個小時的具體時分秒,去執行一個方法。這個方法是自動執行的,極大的減輕了咱們的工做量。數據庫

  發郵件:這個仍是比較常見的吧!註冊什麼的大多都要郵件激活,咱們也能夠用java程序的方式,來給你郵箱發郵件。數組

  提早準備:大概瞭解一下javase中多線程和線程池概念,重點是ThreadPoolTaskExecutor這個類。瀏覽器

 

1.簡單說說異步任務和RabbitMQspringboot

  不知道看了我上面說了異步任務,你們有沒有想到前面說過的一個東西,就是RabbitMQ啊!這個消息隊列,不就是也是這樣的嗎?生產者發消息給交換器以後,就無論了,也許生產者就能夠直接響應用戶響應成功了。而內部也許還有交換器發消息給隊列,而後消費者消費消息,但這個過程就跟用戶就沒什麼關係了,幹嗎要用戶浪費時間在那瞎等呢?服務器

  就我而言,異步任務和RabbitMQ最大的區別應該是訪問量的差別;能夠將異步任務看做是簡化版RabbitMQ 。多線程

  你想啊,假如你作了一個系統,最大訪問量總共那麼點人,你還要去用個RabbitMQ去搞這搞那的,麻不麻煩啊。。。異步

  可是假如你在一家大公司,作的系統是給幾十萬甚至幾百萬用戶用的,那麼確定要用RabbitMQ啊。這個時候若是用異步任務,哪有這麼多空閒線程去給你執行這個任務啊,並且線程到了一個數目以後,效率反而是下降的。

  補充小知識:你們知不知道服務器怎麼處理多個請求的啊?

  假如都是同步任務:請用請求一到,服務器就出用一個線程去執行,而且到了service層以後,假設會有個任務須要幾十秒才能執行完畢;那麼執行到這裏就會卡住了,請求到這裏都要卡住幾十秒,人多的時候可能還要排隊,等時間過了你纔會獲得響應。

  那就等着唄,然而不巧的是,這個時候又有幾千人來來給服務器發請求,因而這幾千人每人等幾十秒,並且因爲服務器又比較水,一會兒開了幾千個線程還有點卡因而要等更長時間。(咳,因此越貴的服務器配置高,線程可以開得多,運行速度快,處理多人請求的能力就很牛),因而這幾千人用了這個系統以後,心中大罵日了狗了哦,下次不再用這個鬼系統了。 

  那假如是異步任務:仍是用訂單/庫存系統舉例,幾千人都在買買買,一時間幾千個訂單請求到controller,而後調用service(注:service仍是跟上面同樣要幾十秒),一到service,判斷是個異步方法,因而趕忙讓處理異步任務的線程過來慢慢處理就好,controller能夠直接響應用戶「訂單成功」。用戶極短期就收到響應,因而能夠繼續買買買。

  這裏就要說個東西,那個處理異步方法的線程哪裏來的啊?實際上是從異步方法線程池裏拿的。你們應該知道鏈接池啊,是處理與數據庫鏈接問題的,還能設置個數,最大超時時間等等,還能防止頻繁的銷燬建立線程的資源消耗。這裏的線程池也差很少,能夠設置個數啊什麼的。。。。後面咱們就會試試簡單的配置一個鏈接池專門處理異步任務。

 

2.簡單使用異步任務

  建立一個簡單的springboot項目,web模塊+1.5.xx版本。

  簡單寫個controller和一個處理邏輯的類,先看看同步處理:

  ok,你能夠測試一下,等5秒鐘瀏覽器纔會響應,emmm...瑪德,等得真煩。。。

 

  測試異步處理,加兩個註解就ok了。

  而後此次就能不超過一秒鐘,就返回響應成功了,大家也能夠本身用System.currentTimeMillis()這個方法去測測時間,這裏就很少說了。

  這裏就須要考慮了,假如訪問量不少,每一個請求都過來調用HelloTask方法,那就要拿到相應數量的處理異步的線程,來處理這個HelloTask方法!

  處理異步任務的線程也是屬於服務器的線程啊,線程數太多服務器會很卡的,默認是有線程池的!可是咱們根據本身項目的需求,因而要自定義線程池的一些配置。

  假如線程池裏就設置最多30個線程(這裏也會有個相似RabbitMq的簡單消息隊列),那麼即便幾千人來調用HelloTask方法,那麼最多也就拿到30個處理異步的線程,來處理這個方法;至於其餘的那麼多請求就丟到請求隊列裏,等這30個線程中某些率先處理完任務的線程就會從這消息隊列中拿任務繼續處理。

 

3.自定義異步任務的線程池

   剛剛查一下資料,其實也是能夠用多線程來作的,只是每次都用多線程比較麻煩,不太小夥伴們能夠試試。

  線程池就至關於包裝了一下多線程的操做,作了不少配置!就相似ArrayList和Object數組的關係。

   

  在下面方法打印當前線程(注意,這裏註解@Async(「本身配置的線程池的名字」),這裏能夠指定配置的哪一個線程池,能夠本身試試,咱們這裏要寫應該是taskExecutor)

 

 而後運行,打開瀏覽器,瘋狂刷新,控制檯打印以下;(注意:能夠把線程池中線程數目弄少一點,把sleep時間調整短一點,就能明顯看到線程不會按順序使用了,而是隨機的!這個本身能夠測試一下)

 

4.給異步方法設置返回值

   前面說的都是異步方法返回值爲void的狀況,可是有的時候咱們要拿到異步方法的返回值。

  這個邏輯是怎麼回事呢?有了返回值還能異步嗎?答案是能夠的。

  舉個例子,當請求到controller,線程就會去執行controller方法,碰到了要執行一個異步方法,因而異步方法立馬返回一個Future對象敷衍controller一下(瑪德,controller真是老實人...),而後繼續執行controller後面的方法,不會停頓;

  這個Future就是異步方法的返回值,只是剛開始尚未數據,等異步方法執行完畢,自動的就會將數據放入Future,比較常見的是利用Future來捕獲異常。

  其中,Future是個接口,實現類是AsyncResult,下面就看看修改後的controller:

 

 

  再看看異步方法內部代碼:

 

  ok,能夠了,運行應用,測試結果以下:

 

  簡單的看了看異步任務的用法,應該仍是比較容易的,用起來也沒什麼難度,就是真實項目碰到的狀況可能就會很複雜,要考慮的狀況比較多了。

相關文章
相關標籤/搜索