併發編程第二部分結構化併發應用程序

看一看這個玩意:
在這裏插入圖片描述

  • poll -->【若隊列爲空,返回null】

  • remove >【若隊列爲空,拋出NoSuchElementException異常】

  • take -->【若隊列爲空,發生阻塞,等待有元素】
    在這裏插入圖片描述
    以上代碼串行執行,但是handleRequest執行很慢,可用以下方案啊,每次請求都創建一個線程,結構上類似於單線程版本,但是每次accept的時候都可以交給線程去處理,然後接受下一個連接
    在這裏插入圖片描述
    由此我們可以得出小結論

  • 任務處理過程從主線程分離出來 ,主循環能更快等到下一個到來的連接,這樣程序完成前面請求後接受新請求,提高響應性

  • 任務並行處理,服務多個請求,例如等待i/o,獲取鎖,獲取資源可用性,提高程序吞吐量

  • 任務處理必須保證線程安全

接下來講到基於生產者——消費者模式的框架Exexutor,生產者提交任務,消費者執行任務
在這裏插入圖片描述
創建一個線程池,固定長度線程池可以容納100個線程
在這裏插入圖片描述
爲每一個請求創建線程
在這裏插入圖片描述
也可以編寫一個單線程執行任務同步執行並返回
在這裏插入圖片描述

線程池
Executor類庫提供了幾個工廠方法

  • newFixedThreadPool :創建固定長度線程池,提交一個任務創建一個線程,直到最大,如果發生Exception結束了,會創建一個新的線程
  • newCachedThreadPool:創建可緩存線程池,如果池當前規模超過處理需求,回收空閒線程,需求增加,增加新線程
  • newSingleThreadExecutor:單線程Executor,創建的單線程如果Exception結束,會創建另一個線程來代替。確保串行
  • newScheduledThreadPool:創建固定長度線程池,以延遲定時方式執行
  • newFixedThreadPool
  • TaskExecutionWebServer:web使用Executor用execute將任務提交到工作隊列,工作線程反覆從隊列取出任務並執行。

線程池由爲每任務分配一個線程百年城基於線程池策略,web服務器不會在高負債情況下失敗,可實現調優、管理、監視、記錄日誌、報錯、so on。。。。。。如果不正確關閉Executor JVM無法結束

Executor生命週期管理方法,調用shutdown即可
在這裏插入圖片描述
延遲與週期任務
可以用ScheduledThreadPoolExecutor

future 任務生命週期只進不退
get()方法取決於任務狀態 未開始?運行?已完成?如果已完成,任務拋出Exception,未完成get將阻塞到完成
在這裏插入圖片描述
Callable和Future表示這些協同任務的交互,創建Callable下載所有圖像,提交到ExecutorService,返回Future描述任務的執行情況。主任務需要的時候會等待future.get執行結果,幸運的話,已經下載好了,或者已經提前在下載中了。
在這裏插入圖片描述
異常包括兩一個是中斷,一個是遇到一個Exception。

創建一個BlockingQueue保存計算結果,計算結束調用done,提交任務,先包裝成QueueingFuture,改寫done方法,訪日BlockingQueue
在這裏插入圖片描述

使用CompletionService實現頁面渲染器,每個圖像下載都創建獨立任務,線程池執行,串行轉並行
在這裏插入圖片描述
多個任務提交到ExecutorService獲取結果 InvokeAll方法的參數爲一組,返回一組future,執行完畢,中斷,超時,InvokeAll將返回。超時後,未完成的被取消
在這裏插入圖片描述
在這裏插入圖片描述
下面代碼用了素數生成器
。,執行1s後取消,現實中銀行用此策略停止支付

在這裏插入圖片描述

如果生產者速度超越消費者,那麼put一直被阻塞,通過中斷來取消
在這裏插入圖片描述
線程在阻塞或者進行重要的工作前檢查中斷狀態
在這裏插入圖片描述
啓動線程,timedRun執行join方法,檢查任務中是否有異常拋出,在調用timedRun線程中再次拋出一場,由於throwAble在兩個線程共享,所以被聲明爲volatile
在這裏插入圖片描述
將任務交給ExecutorService,通過future.get來獲取結果,如果拋出一場,則通過future取消
在這裏插入圖片描述
同步讀取套接字,傳給processBuffer
在這裏插入圖片描述

在這裏插入圖片描述
以下多生產者單消費者,調用log是生產者, LoggerThread相當於消費者,如果消費者的處理速度低於生產者生成速度,BolckingQueue將阻塞生產者,直到日誌線程有能力處理新的日誌消息。直到日誌線程有能力處理日誌消息。
在這裏插入圖片描述
但還有一個終止日誌線程的方法,避免jvm無法正常關閉,如果用take響應中斷,會丟失等待被寫入日誌的消息。其他線程在調用log也被阻塞,因爲log的消息隊列是滿的,需要同時取消聖生產者消費者,可以用計數器來控制

在這裏插入圖片描述

關閉iExecutorService,用shutdown正常關閉速度慢,等到任務執行結束後關閉,用shutdownNow強行關閉速度快,風險更大,未執行就關閉。可以託管給ExecutorService管理
在這裏插入圖片描述

另一種關閉生產者消費者方式是用"毒丸對象",當得到這個對象,立即停止,提交毒丸之前,所有工作都會被處理,生產者提交讀完後將不會提交任何工作
在這裏插入圖片描述
在這裏插入圖片描述
僅當生產消費者都一直的情況下才可以用毒丸對象,每個生產者向隊列中放1毒丸,消費者接收到N個毒丸才停止

只執行一次的服務,當所有任務都處理完成後才返回,可以通過私有Executor簡化服務生命週期管理,Executor生命週期由此方法控制
如下代碼checkMail在多臺主機上並行檢查新郵件,創建Executor,向每臺主機提交任務,任務執行完關閉Executor
在這裏插入圖片描述
應該找出哪些任務已經開始但沒有正常完成getCancelledTasks返回被取消的任務清單。
在這裏插入圖片描述
如圖當爬蟲關閉的時候,希望保持狀態以便重啓的時候繼續,getPage將記錄未開始或被取消的任務,重啓就可以把抓取任務加入任務隊列
在這裏插入圖片描述

jvm可以正常關閉也可以強行關閉,最後一個正常線程結束,或者調用了System.exit。

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