日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OO_Unit2_多线程电梯

發布時間:2025/5/22 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OO_Unit2_多线程电梯 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CSDN博客鏈接

一、第一次作業

1.需求分析

單部多線程傻瓜調度(FAFS)電梯

2.實現方案

輸入接口解析

  • 類似于Scanner,我們使用ElevatorInput進行阻塞式讀取(第一次作業較簡單,沒有單獨開一個線程,而是直接放在主控類Main中)
  • 讀取到null時,表示已經讀取完畢,可以退出
  • 本接口只會讀取到正確的請求,錯誤的將跳過并在stderr輸出錯誤信息(不影響程序本身運行,也不會引發RUNTIME_ERROR)
  • 記得在最后進行close()
while (true) {PersonRequest request = elevatorInput.nextPersonRequest();if (request == null) {break;} else {queue.add(request);} } elevatorInput.close();

建立類圖 第一次作業較為簡單,沒有多考慮,建立了:

  • 一個Elevator線程(實現run方法)
  • 一個管理請求的隊列Queue(線程安全,用于管理請求隊列的ArrayList,這里可以①繼承自ArrayList;②由ArrayList組成;方法②更好,避免了繼承帶來的麻煩問題,并可以將隊列進行封裝:少用繼承,多用組合)
  • 其中:細實箭頭代表包含關系,Elevator含有一個指向Queue的指針,用于訪問Queue中的請求。
  • 主控類初始化時間戳,創建Queue及Elevator后調用Elevator.start(),最后才開始輸入請求。

實現思路

主控類主動向Queue中輸入請求put,Elevator向Queue中請求拿出請求get,兩者需要互斥:syncronized。

  • 在Elevator中,第一次直接使用了輪詢:
while (!getEnd() || queue.hasNext()) {try {request = queue.getRequest();...} catch (Exception e1) {stay(circleTime);// 每隔circleTime判斷一次請求} }
  • 請求結束時,Main調用List中requestEnd方法,Elevator讀取List中End:getEnd
//List里方法,Main和Elevator分別訪問,需要互斥;在調用requestEnd方法結束時需要notify synchronized void requestEnd() {end = true;notifyAll(); }synchronized boolean getEnd() {return end && list.isEmpty(); }

3.測試及修復

測試思路

此次作業相對簡單,測試的思路也并不復雜,只需要按照指導書對每一種不同的省略輸入進行測試即可

bug修復

本次作業由于使用了輪詢機制,cpu占用時間較長,在第二次作業中修復此問題

二、第二次作業

1.需求分析

單部多線程可捎帶調度(ALS)電梯

2.實現方案

輸入接口解析

同第一次,只是請求的樓層變成了:電梯樓層:-3層到-1層,1層到16層,共19層

建立類圖

Main建立了Client 線程和 List請求隊列就結束了,再由List創建Worker,典型的線程池(Worker Thread)結構:

TimableOutput.initStartTimestamp(); List list = new List(); Client client = new Client(list); client.start();

  • 如圖,Client Worker各有一個指向List的指針。而List創造并指向Worker;List類中含有private ArrayList<PersonRequest> list;

    實現思路
    Client主動向List中輸入請求put,Worker向List中請求拿出請求get,兩者需要互斥:syncronized,改掉了輪詢機制。
  • 對于get方法,沒有請求時需要在原地等待,再由put喚醒。
synchronized boolean get() {while (list.isEmpty()) {try {if (end) {return false;//等待之前判斷是否結束了請求}wait();} catch (InterruptedException e) {e.printStackTrace();}}getOne();//直接分配一個請求;前提:list非空getAnother();//在已有的隊列中尋求其他請求,并放入Workerreturn true; }

3.測試及修復

結構分析

  • 復雜度分析(超標及整體)
Methodev(G)iv(G)v(G)
Worker.next()9610
ClassOCavgWMC
Client24
List321
Main11
Worker2.6748
Packagev(G)avgv(G)tot
xxx2.9683
- 如表,Worker.next的ev(G)和v(G)高:- 基本復雜度:來衡量程序**非結構化程度**的;高意味著**非結構化程度高**,難以模塊化和維護- 圈復雜度:用來衡量一個模塊判定**結構的復雜程度**,數量上表現為獨立路徑的條數;圈復雜度大說明程序代碼可能**質量低且難于測試和維護**- 模塊設計復雜度:模塊設計復雜度是用來衡量模塊判定結構,即模塊和其他模塊的調用關系。意味模塊**耦合度高**,這將導致模塊**難于隔離、維護和復用**。```private int next() {int i;if (up) {for (i = minFloor; i <= maxFloor; i++) {if (i != 0) {if (getStop(i)) {break;}}}} else {for (i = maxFloor; i >= minFloor; i--) {if (i != 0) {if (getStop(i)) {break;}}}}if (i > maxFloor || i < minFloor) {return -999;}return i;}```- 這段用于尋找下一個停靠樓層的代碼希望在上升時由低到高遍歷,下降時由高到低遍歷。- 寫的很丑,結構層次化差,分支條件多。很容易出錯,也很難發現錯誤的地方。- 異常時草率地返回了一個`-999`不太負責,應該直接拋出異常`throw new IllegalStateException("No Stop");`以后可以更好地發現錯誤。 - 其余的數據在正常范圍之內
  • 依賴關系分析

    ClassCyclicDcyDcy*DptDpt*
    Client31313
    List32333
    Main32323
    Worker32313

    從表中得到,各個類之間耦合關系在正常范圍內。

測試思路

  • 本次使用了隨機自動化測試,步驟如下:
    • 生成隨機數據
    • 實現定時輸入(評測機的輸入)
    • 驗證輸出的正確性和與輸入的對應
    • 將上述操作封裝入批處理進行循環
  • 利用 python 的 random 庫生成若干條隨機數據
  • # make.py t = round(random.uniform(0,100),1) #生成[0,100)間的隨機小數并保留一位小數 ID = random.randint(0,99999999) fromfloor= random.randint(-3,20) tofloor = random.randint(-3,20) println("[%.1f]%d-FROM-%d-TO-%d" %(t,ID,fromfloor,tofloor))
  • 利用黑箱投放數據
    • 需要將項目打包成.jar文件(有dl同學寫出了builder腳本:直接通過.zip直接生成.jar文件,形成了如下文件樹)
      ├──src │ ├─ Archer.jar │ ├─ Berserker.jar │ ├─ Caster.jar | ├─ .... | └─ Alterego.jar ├──lib │ ├─ elevator-input-hw3-1.4-jar-with-dependencies.jar │ └─ timable-output-1.1-raw-jar-with-dependencies.jar └──pat.py
    • 使用到hdl的黑箱投放已經生成好的數據
  • 驗證:
    對一些基本條件進行檢驗:
    • ①所有乘客都在fromfloor上電梯,并最終到達tofloor,中途可能有轉梯
    • ②in,out需要在開關門之間
    • ③電梯連續地到達各樓層,相鄰兩層間時間不少于電梯運行時間
  • shell 腳本運行批處理文件
  • python make.py > make.txt java -jar my.jar < make.txt > result.txt cat python judge.py < result.txt

    bug修復

    最初使用的方法是當且僅當電梯為空輸入請求時List類將請求放入電梯中,但這樣很可能出現異步的情況:

    [0.0]1-FROM-1-TO-15 [0.4]2-FROM-2-TO-14

    當電梯在1樓接到人以后,目的層按15層,可是由于第二個請求是異步的,沒法正好在電梯到達2樓前收到消息并挺下來。電梯很有可能走過了第二層才接到第二個請求。使得2號乘客在14樓下卻沒有上電梯。

    我嘗試著讓List優先級變高,Worker使用yield方法,但都沒有解決線程不安全問題。最后只能讓Worker沒到達一層就訪問一次List看看有沒有可以攜帶的請求。

    這樣使得線程之間關系明了,不會出錯了,但是明顯因為每層都要訪問,使得效率降低了,由于處理速度很快,基本上每隔3層才多出10ms,這樣犧牲了小部分性能提升了線程安全性,簡化了邏輯,是很值得的。

    三、第三次作業

    1.需求分析

    在第二次作業的基礎上,加入了多個電梯,并設置最大允許人數和允許停靠樓層。

    • 電梯數量:3部,分別編號為A,B,C
    • 電梯可運行樓層:-3-1,1-20
    • 電梯可停靠樓層:
      • A: -3, -2, -1, 1, 15-20
      • B: -2, -1, 1, 2, 4-15
      • C: 1, 3, 5, 7, 9, 11, 13, 15
    • 電梯上升或下降一層的時間:
      • A: 0.4s
      • B: 0.5s
      • C: 0.6s
    • 電梯最大載客量(轎廂容量)
      • A:6名乘客
      • B:8名乘客
      • C:7名乘客

    2.實現方案

    建立類圖

    本次多線程較為復雜,按照老師對于Worker Thread的提示,我詳細看過了《圖解java設計模式》的那一章,自己也畫出了一個大致的類圖:

    如圖,細箭頭表示包含,粗箭頭表示繼承。在第二次作業的基礎上,運用了OCP原則,沒有直接修改Worker類,而是使其繼承了一個子類NewWorker,在新的類中重寫父類方法,以保證第三次作業所做的能同時兼容第二次。

    對于PersonRequest也繼承了子類Request,并讓它也成為了一個線程,并擁有了指向List和Client的指針。

    圖中所有的線程包括:Worker, NewWorker, Client, Request

    實現思路

    Client主動向List中輸入請求put,Worker向List中請求拿出請求get,對于特殊請求Request(不能由一個電梯完成的)分兩次向電梯發送請求,三者需要互斥。

    其中,Request類比較特殊

    • 在Client中判斷此請求是否被接受,不被接受則開啟一個新的Request線程并設置一個原子信號量sem記錄線程數量,否則Request就是一個簡單的PersonRequest
    PersonRequest a = elevatorInput.nextPersonRequest();if (a == null) {break;}Request request = new Request(a.getFromFloor(),a.getToFloor(), a.getPersonId(), list, this);if (list.accept(request)) {list.put(request);} else {sem.getAndIncrement();new Thread(request).run();}
    • 在Request類中則查找中間轉梯層,并將其切分為兩個Request,按次序投放:在投放完第一個后,需要調用waitFor(request1),直到List和電梯中都不存在request1再投放第二個。
    Request request1 = new Request(getFromFloor(), i,getPersonId(), list, client); Request request2 = new Request(i, getToFloor(),getPersonId(), list, client); list.put(request1); list.waitFor(request1); list.put(request2); client.decrease(); client.finishAndNotify();
    • 這樣將Request單獨開一個線程,大大簡化了容器類List的設計,不需要使其成為一個線程。并且線程之間的交互關系簡單明了,即使有新的需求:需要換成多次,也能輕松完成。缺點是:當這樣換乘的請求過多,使得線程也很多,cpu調度的效率會下降。

      3.測試及修復

      結構分析

    • 復雜度分析(超標及整體)

    Methodev(G)iv(G)v(G)
    List.hasRequest(Request)535
    Request.run()61919
    Worker.moveOne(int,boolean)414
    Worker.next()9610
    ClassOCavgWMC
    Client28
    List3.0840
    Main11
    NewWorker2.5528
    Request520
    Worker2.2456
    Packagev(G)avgv(G)tot
    xxx3174

    可以看到,Request.run()方法三項均超標。這一個run方法具有很強的面向過程特性:

    整個run()方法寫了60行,可以說對各種情況都進行了討論并分支。違背了SOLID中的SRP單一職責原則,更好的方法是對每種特例寫一個函數,并逐層調用,使得代碼結構清晰,而且容易修正。這次的2個bug都是出現在Request.run()方法中的,由此可見,一個清晰的代碼結構甚至能減少錯誤率。

    • 依賴關系分析
    ClassCyclicDcyDcy*DptDpt*
    Client52625
    List54655
    Main52645
    NewWorker55615
    Request54645
    Worker53635

    從表中得到,各個類之間耦合關系依然在正常范圍內,說明這次結構設計上問題不大。

    bug修復

  • 第一個bug出現在Request.run()中:本來希望min和max依次代表請求最低層上一層、最高層下一層:
  • int min = Math.min(getFromFloor(), getToFloor()) + 1; int max = Math.max(getFromFloor(), getToFloor()) - 1;

    卻忽略了最低層正好是-1,最高層正好是1情形,按上面的算法都到了第0層,出現了數組轉換越界。只好新增了Worker.moveOne(int floor,boolean up)方法,up為true是上移一層,否則下移一層。

    int min = Math.min(getFromFloor(), getToFloor()); int max = Math.max(getFromFloor(), getToFloor()); //md,忽略了min和max可能因為from 與to正好是1,-1而出現0!!!!! min = Worker.moveOne(min, true); max = Worker.moveOne(max, false);
  • 第二個bug也出現在Request.run()中,對于奇怪的請求:3->4,3->2,原本在兩層之間找換乘失效了,而我正好沒有考慮到這種情況:
  • //臨界情況 if (min > max) {if (getFromFloor() == 3) {if (getToFloor() == 4) {dispatch(5); //3->4拆解成3->5->4} else if (getToFloor() == 2) {dispatch(1); //3->4拆解成3->1->2}} }

    轉載于:https://www.cnblogs.com/RyanSun17373259/p/10762123.html

    總結

    以上是生活随笔為你收集整理的OO_Unit2_多线程电梯的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 一本一道久久a久久精品蜜桃 | 久草aⅴ| 日韩黄色成人 | 日韩视频网站在线观看 | 国产无套免费网站69 | 99er精品视频 | 26uuu精品一区二区在线观看 | www.av网 | 一本色道久久加勒比精品 | 欧美精品一区二区三区视频 | 丁香婷婷成人 | 黄色精品一区二区 | 亚洲一线在线观看 | 欧美久久久久久久 | 亚洲国语 | 日本韩国在线观看 | 国内9l自拍 | 78m78成人免费网站 | 无码av免费精品一区二区三区 | 日本成人黄色 | 日韩欧美视频一区二区三区 | 黄色网免费观看 | 欧美成人片在线 | 国产av一区二区三区最新精品 | 91成人精品一区在线播放 | 亚洲一区二区三区成人 | 九九热综合 | 性色AV无码久久一区二区三 | 丰满熟妇肥白一区二区在线 | 亚洲黄色片免费看 | 色综合久久88色综合天天免费 | 亚洲亚洲人成综合网络 | 天海翼av在线播放 | av免费在线观 | 爆操网站 | 青青草在线免费 | 国产乱人乱精一区二视频国产精品 | 成人欧美一级特黄 | 少妇被黑人到高潮喷出白浆 | 日韩av中文字幕在线 | aaa一区二区三区 | 日韩经典三级 | 欧美无遮挡高潮床戏 | 日韩一级高清 | 天天干天天操天天拍 | 色婷婷综合五月 | 欧美大片aaa | 秋霞午夜鲁丝一区二区老狼 | 国产福利专区 | 五月综合激情日本mⅴ | 岛国精品一区二区三区 | 色综合九九 | 欧美一级啪啪 | 国产极品美女高潮无套嗷嗷叫酒店 | 亚洲毛片在线免费观看 | 色哟哟一区二区三区四区 | 51成人| 动漫美女揉胸 | 国产处女| 欧美成人高清视频 | 一级黄色a| 久久久久99精品成人片试看 | 999精品网站 | 日本三级午夜理伦三级三 | 国产97色在线 | 国产 | 男女无遮挡免费视频 | 男男gay动漫 | 国产+高潮+白浆+无码 | 国产成人一区二区在线 | 淫综合网 | 老司机av影院 | 精品国产乱码久久久久久108 | 国产成人久久精品 | 法国少妇愉情理伦片 | 亚洲欧美精品在线观看 | 蜜桃视频污 | 69日影院 | 男男全肉变态重口高h | 欧美熟妇毛茸茸 | 性做久久| 99这里 | 男人的天堂色 | 男女一级片 | 黄瓜视频91 | 日本一区二区三区久久 | www.xxx日韩 | 91欧美一区二区三区 | 老狼影院伦理片 | 香蕉色综合 | 伊人一级 | yy1111111| 久艹视频在线观看 | 免费在线视频一区二区 | 污污视频在线免费观看 | 日韩精品视频一区二区在线观看 | 美女扒开大腿让男人桶 | 欲求不满在线小早川怜子 | 99re在线视频| 日本边添边摸边做边爱 |