OO學習體會與階段總結(多線程程序)

 前言

  在最近一個月的面向對象編程學習中,咱們進入了編寫多線程程序的階段。線程的建立、調度和信息傳遞,共享對象的處理,線程安全類的編寫,各類有關於線程的操做在必定程度上增長了近三次做業的複雜度與難度,帶來了不小的考驗。本文經過分析總結近三次做業的完成狀況,分享我對與多線程編程的一些看法與體會。算法

 

 


 

做業總結分析

多線程電梯調度

(1)題目簡述

  實現具備捎帶功能的電梯調度系統,調度電梯數量爲3部。編程

(2)程序設計

  • 本系統的大體結構與以前的單線程電梯調度系統相似,主要由輸入處理、請求調度、電梯模擬三大部分組成。
  • 根據行爲的併發特徵,爲這三大部分各設計了一類線程來實現其功能。分別爲輸入監聽線程、請求調度線程、電梯線程。
  • 系統中的共享資源主要是請求隊列,根據請求隊列的類型分紅了輸入隊列與執行隊列。兩者繼承了請求集合類,並將這兩個類編寫成線程安全類。
  • 根據生產者-消費者模型構造線程交互方法。
  • 具體類圖以下:

  • 時序圖:數組

(3)程序分析

  • 複雜度度量:

     

  • 分析:
    • 在存儲請求隊列時採用了數組的數據結構。進行請求隊列的增減操做時須要遍歷數組,致使了相關方法循環複雜度較高。因爲運用了長度變量控制遍歷的邊界,這些方法不會出現危險。能夠考慮使用集合類管理此類數據,以減少代碼的複雜性,增長可維護性。
    • 線程類的run方法過於複雜,使得該方法的複雜度異常的高。出現該問題主要因爲對於線程類的功能的理解不夠到位。應當將線程的行爲細化,並根據線程運行時須要執行的不一樣操做編寫相應的方法以供線程調用。這樣能提升線程類的可維護性。
  • 數據統計:

    

 

(4)問題分析

  本次做業的問題主要出如今如下兩個方面:安全

  • 捎帶請求處理:本次做業沒有采用前幾回做業處理捎帶請求的方法,而是根據電梯的運行將分配到的請求按照到達前後順序構造隊列,電梯按照隊列頭改變運行狀態便可。可是在將新請求插入隊列的部分,邊界判斷出現了錯誤,致使當電梯中止時新請求的插入位置出錯。最終使電梯運行路線出錯。
  • 輸出格式:對於不合法的輸入,輸出時的格式不對。更改輸出格式能夠改正。

  本次做業使第一次編寫多線程程序。因爲對於每一個線程的運行過程的理解不足,我在最初的程序構架時遇到了比較大的困難。尤爲是在共享類中鎖的運用以及線程類的run方法的功能的設計上,經歷了屢次刪除重寫的過程。在必定程度上,這致使了我在類的設計、調度算法設計等方面有了很多疏忽。最終使得本次做業的完成效果通常。此外,在線程調度方面,本次做業較好的運用了課內講的模型。經過此次的鍛鍊,我對於多線程編程的大致框架有了比較深入的認識,爲接下來的學習打下了鋪墊。數據結構


 

IFTTT

(1)題目簡述

  實現IF-THIS-THEN-THAT的文件監控與操做系統。多線程

(2)程序設計

  • 通過分析,程序大體分爲文件快照獲取、監控事件觸發、監控事件任務執行三部分。併發

  • 根據行爲的併發特徵,爲每一個監控事件開啓一個線程,實現監控功能;而且設計一個負責實時輸出的線程。
  • 具體類圖以下:框架

  • 時序圖:學習

(3)程序分析

  • 數據統計:測試

  

  • 複雜度分析:

  

  • 分析:

    • 在構造文件系統的遍歷樹是採用了一維的線性數據結構,每次獲取快照時都須要按深度遞歸遍歷監控範圍內的全部文件,致使獲取快照的相關方法的複雜度較高。在優化的方面,能夠考慮改用集合類中的樹結構或者哈希表的方式對監控範圍內的文件進行預處理(如編碼),減少以後的工做量。此外還能夠直接使用現有庫中的獲取快照的方法。

    • 本次做業對與線程類中的run方法進行了必定的精簡。相較於上次做業,複雜度有了必定的下降,但仍然是全部方法中最高的。可能的緣由是我在最初設計時爲單一線程分配了過多的功能。就本次做業而言,能夠按照觸發器的不一樣將監控線程進行分化。並且還能夠將快照獲取功能分離成單一線程,經過一個線程安全類與監控線程傳遞信息。

(4)問題分析

  本次做業的問題主要出如今文件地址的管理方面。在程序中,每一個文件都使用的是絕對地址格式。絕對地址有多種可識別格式,但經過File類提供的方法從File對象中獲取的絕對地址僅有一種格式。因爲在先後快照對比是經過字符串比較實現的,因此可能因爲格式問題致使錯誤。將格式同一後能夠解決。

  在本次做業中最重要的部分就是文件信息的同步。因爲文件操做是線程不安全的,因此在完成做業的過程當中,我用了至關多的時間在設計線程安全類和快照獲取功能上,最終得到了不錯的效果。但在類功能的設計上還顯得有些冗雜,有挺大的改進空間。

 


模擬出租車打車系統

(1)題目簡述

  實現100輛出租車的搶單調度系統。

(2)程序設計

  • 交互關係分析:

    • 乘客交互的數據特徵:提供請求產生時間、乘客位置信息、目的地位置;返回請求的處理結果。
    • 乘客交互的時間特徵:不定時產生乘客請求;請求產生3s後返回處理結果。
    • 出租車交互數據特徵:獲取出租車的位置信息、服務狀態和信用信息;返回其搶單結果和須要服務的乘客位置信息與目的地位置。
    • 出租車交互時間特徵:以100ms爲週期獲取。
  • 對象識別與構造:

    • 須要管理的數據及管理手段:
      1. 乘客的請求:

        • 監聽獲取乘客發出的請求。
        • 維護接受的請求集合。
      2. 乘客請求的響應窗口:

        • 根據請求的位置與時間創建相應的搶單窗口。
        • 維護相應窗口集合。
      3. 出租車:

        • 維護出租車信息的更新。

        • 維護出租車集合。

  • 識別併發行爲:

    • 系統與乘客之間交互相對獨立,因爲只由控制檯輸入,使用一個線程設計用於與控制檯輸入交互。

    • 出租車的行爲具備顯著的重複模式,而且相對獨立,使用一種線程設計,分別描述每一輛出租車行爲。

    • 對於獲取的乘客請求的處理與分配具備重複性,而且相對獨立,使用一種線程設計來實現功能。

    • 信息輸出相對獨立,使用一個線程實現。

  •  具體類圖以下:

  • 時序圖:

(3)程序分析

  • 數據統計:

  

  • 複雜度分析:

  

  • 分析:

    • 相較於上次做業,本次做業方法的複雜度有了明顯的下降(不考慮現成的GUI代碼)。在最初設計的時候,我就考慮到了SOLID等原則,並儘可能使設計的類符合以上的原則,作出了風格上的改變。其中線程類的設計上,儘可能分配更少、更簡潔的功能,使其僅需完成線程部分必要的代碼。從而使得整個程序的可維護性與可讀性有了至關大的提升。

(4)問題分析

  在測試階段個人程序沒有被發現問題。可是在本身檢查的時候發現了很多的潛在問題:

  • 地圖管理:本次做業我使用了gui中給好的地圖管理類,使用矩陣管理地圖。每當出租車接單時都須要調用廣度遍歷方法來獲取最短路徑。這使得出租車在路徑的選擇上缺少功能延展性,只能走最初設定好的路線,沒法適應路況的變化。
  • 出租車管理:在本次做業中,我爲了簡單將全部的出租車都管理在了同一個數組中,將出租車狀態保存在了出租車各自的對象中。若是能將不一樣狀態的出租車分離,用不一樣的策略去管理,則可以使程序的延展性更高。

 


總結

  通過了這三次的多線程編程做業,經過分析做業中的問題,我對於線程的調度與線程的安全有了至關深刻的認識。從宏觀上來看,每一個線程都在同時運行,但微觀上看他們是在JVM的調度之下按原子操做交替執行。若是每一個線程間相互獨立,JVM調度的不肯定性不會影響程序的可再現性。但就像電梯中的請求隊列、IFTTT中的文件信息、出租車系統的請求和出租車信息,每一個線程間難以免地會有共享的數據,此時就須要經過同步、互斥的手段防止JVM調度的不肯定性破壞程序的可再現性。一般,經過鎖機制就可以實現這些功能。可是,在共享關係比較複雜的狀況下,單純的使用鎖機制並不必定可以達到預期的效果。這時就須要一種模式化的線程安全保護措施。那就是線程安全類。編寫線程安全類就比如爲已有的功能代碼加上一層外皮,其內部代碼保證功能的實現,外部接口保證入口的互斥,從而實現線程安全。但這又帶來了另外一個問題:同步部分的代碼長度對多線程效率的影響。進而對於臨界區的功能安排應當儘可能精簡,以免對多線程機制的浪費。

  此外,通過了對面向對象思想的學習,我認識到了面向對象程序設計的12大基本原則,而且將其實踐到最近的一次做業當中。在親自編寫代碼的過程當中,我體會到這些原則最核心的想法就是:設計具備層次性、代碼具備可延展性。在設計時就要從最外層的交互設計,一層層深刻,到內部對象的建模、對象間交互,再到類內部的設計。這個設計就是對整個環境與系統的逐層深刻,將各個功能逐層分離,最終造成相似樹狀的類設計。而在編寫代碼的時候不該當僅關注於當前的功能實現,更應當想到更多同類型的操做。換句話說就是編寫出的方法、類不該當進可以實現特例操做,而更應當面向更爲抽象、更爲通用的層次上。

相關文章
相關標籤/搜索