ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BUAA_OO_2022_Unit_2_Summary

2022-04-26 23:03:08  阅读:181  来源: 互联网

标签:OO 2.0 1.0 BUAA Elevator Controller GlobalController PersonRequest Unit


零、目录

  • 程序设计构架
    • 第一次作业
    • 第二次作业
    • 第三次作业
    • 协作图
  • 调度器设计
  • 同步块与锁分析
  • 电梯逻辑分析
  • 程序BUG分析
  • 自测/互测策略
  • 心得体会

一、程序设计构架

第一次作业
  • 需求简述:

    模拟一个多线程实时电梯系统,各楼座有且仅有一台纵向电梯,处理已知起终点的同楼座乘客请求。

  • 代码构架:

    |- Unit2:主类
    |- InputHandler:输入线程
    |- Controller:各楼座候乘表
    |- Elevator:电梯线程
    |- OutputHandler:输出处理
    

    采用生产者-消费者设计模式,托盘为各楼座候乘表,即实际上有5张候乘表。

    同一楼座的电梯共享该楼座的候乘表,读写信息均在候乘表中加锁实现,避免几个线程之间直接交互以及数据不同步的问题。

    对 TimableOutput 加锁封装为输出处理类,避免出现以下情况导致输出时间戳非递增:

    1获取时间戳 --> 2获取时间戳 --> 2输出 --> 1输出
    
  • 规模分析:

    共221个代码行

  • 复杂度分析:

    method ev(G) iv(G) v(G)
    Controller.addRequest(PersonRequest) 1.0 1.0 1.0
    Controller.getRequests() 1.0 1.0 1.0
    Controller.isInputAlive() 1.0 1.0 1.0
    Controller.setInputAlive(boolean) 1.0 1.0 1.0
    Controller.setRequests(ArrayList) 1.0 1.0 1.0
    Elevator.Elevator(char, int, Controller) 1.0 1.0 1.0
    Elevator.move(long) 1.0 1.0 2.0
    Elevator.openAndClose() 1.0 13.0 15.0
    InputHandler.InputHandler(ElevatorInput, HashMap) 1.0 1.0 1.0
    OutputHandler.initStartTimestamp() 1.0 1.0 1.0
    OutputHandler.println(String) 1.0 1.0 1.0
    Unit2.main(String[]) 1.0 3.0 3.0
    InputHandler.run() 3.0 6.0 6.0
    Elevator.run() 9.0 22.0 25.0
    Total 24.0 54.0 60.0
    Average 1.71 3.86 4.29
第二次作业
  • 需求简述:

    模拟一个多线程实时电梯系统,初始各楼座有且仅有一台纵向电梯;可动态增加横向、纵向电梯;处理已知起终点的同楼座或同楼层乘客请求。

  • 代码构架:

    |- Unit2:主类
    |- InputHandler:输入线程
    |- GlobalController:总候乘表
    |- Controller:各楼座/层候乘表
    |- Elevator:电梯线程
    	|- ElevatorP:横向电梯线程
    	|- ElevatorV:纵向电梯线程
    |- OutputHandler:输出处理
    

    仅为完成本次作业的代码与第一次作业基本相同,只是将电梯线程抽象出来——把方向计算、距离计算抽象成子函数,并在横向、纵向电梯类内具体实现这些操作。此时,两类电梯的开关门、运行、捎带等策略完全一致,可以将第一次作业的代码完全复用,并且没有出现大段重复代码。

    因上述实现较为简单,我在本次作业中尝试提前实现换乘。将原来的一级托盘结构更改为二级托盘结构,分别装载所有请求和具体座/层请求。详见后文“调度器设计”。

  • 规模分析:

    共489个代码行

  • 复杂度分析:

    method ev(G) iv(G) v(G)
    Controller.addRequest(PersonRequest) 1.0 1.0 1.0
    Controller.getRequests() 1.0 1.0 1.0
    Controller.isInputAlive() 1.0 1.0 1.0
    Controller.setInputAlive(boolean) 1.0 1.0 1.0
    Controller.setRequests(ArrayList) 1.0 1.0 1.0
    Elevator.Elevator(int, GlobalController, Controller) 1.0 1.0 1.0
    Elevator.getBlock() 1.0 1.0 1.0
    Elevator.getDirection() 1.0 1.0 1.0
    Elevator.getEleId() 1.0 1.0 1.0
    Elevator.getFloor() 1.0 1.0 1.0
    Elevator.inDir(PersonRequest) 1.0 1.0 1.0
    Elevator.openAndClose() 1.0 5.0 5.0
    Elevator.setBlock(char) 1.0 1.0 1.0
    Elevator.setCtrlKey(String) 1.0 1.0 1.0
    Elevator.setDirection(int) 1.0 1.0 1.0
    Elevator.setFloor(int) 1.0 1.0 1.0
    Elevator.takeIn(String) 1.0 11.0 11.0
    Elevator.takeOff(String) 1.0 4.0 4.0
    Elevator.waitInDir(PersonRequest) 1.0 1.0 1.0
    ElevatorP.ElevatorP(int, int, GlobalController, Controller) 1.0 1.0 1.0
    ElevatorP.isFrom(PersonRequest) 1.0 1.0 1.0
    ElevatorP.isTo(PersonRequest) 1.0 1.0 1.0
    ElevatorP.move(long) 1.0 4.0 4.0
    ElevatorP.reqDir(PersonRequest) 1.0 1.0 3.0
    ElevatorP.waitDir(PersonRequest) 1.0 1.0 3.0
    ElevatorV.ElevatorV(char, int, GlobalController, Controller) 1.0 1.0 1.0
    ElevatorV.isFrom(PersonRequest) 1.0 1.0 1.0
    ElevatorV.isTo(PersonRequest) 1.0 1.0 1.0
    ElevatorV.reqDir(PersonRequest) 1.0 1.0 1.0
    ElevatorV.waitDir(PersonRequest) 1.0 1.0 1.0
    GlobalController.GlobalController() 1.0 1.0 1.0
    GlobalController.addController(ElevatorRequest) 1.0 2.0 2.0
    GlobalController.addElevator(ElevatorRequest) 1.0 3.0 3.0
    GlobalController.addElevatorP(ElevatorRequest) 1.0 2.0 2.0
    GlobalController.addElevatorV(ElevatorRequest) 1.0 2.0 2.0
    GlobalController.infoInputKilled() 1.0 2.0 2.0
    GlobalController.initControllers() 1.0 2.0 2.0
    GlobalController.initElevators() 1.0 2.0 2.0
    GlobalController.withoutTransfers() 1.0 1.0 1.0
    InputHandler.InputHandler(ElevatorInput) 1.0 1.0 1.0
    OutputHandler.initStartTimestamp() 1.0 1.0 1.0
    OutputHandler.println(String) 1.0 1.0 1.0
    Unit2.main(String[]) 1.0 1.0 1.0
    GlobalController.addNextRequest(String, PersonRequest) 3.0 4.0 5.0
    InputHandler.run() 3.0 6.0 6.0
    ElevatorV.move(long) 4.0 4.0 4.0
    Elevator.ifOpen() 5.0 11.0 12.0
    Elevator.run() 5.0 12.0 14.0
    GlobalController.addRequest(PersonRequest) 7.0 8.0 10.0
    Total 70.0 116.0 126.0
    Average 1.43 2.37 2.57
第三次作业
  • 需求简述:

    模拟一个多线程实时电梯系统,初始各楼座有且仅有一台纵向电梯、1层有且仅有一台可达所有楼座的横向电梯;可动态增加横向、纵向电梯,新电梯可自定义限载人数、运行速度、(横向电梯)可达楼座;处理已知起终点的任意乘客请求。

  • 代码构架

    |- Unit2:主类
    |- InputHandler:输入线程
    |- GlobalController:总候乘表
    |- Controller:各楼座/层候乘表
    |- Elevator:电梯线程
    	|- ElevatorP:横向电梯线程
    	|- ElevatorV:纵向电梯线程
    |- OutputHandler:输出处理
    
  • 规模分析:

    共557个代码行

  • 复杂度分析:

    method ev(G) iv(G) v(G)
    Controller.addElevator(ElevatorRequest) 1.0 1.0 1.0
    Controller.addRequest(PersonRequest) 1.0 1.0 1.0
    Controller.getElevators() 1.0 1.0 1.0
    Controller.getRequests() 1.0 1.0 1.0
    Controller.isInputAlive() 1.0 1.0 1.0
    Controller.setInputAlive(boolean) 1.0 1.0 1.0
    Controller.setRequests(ArrayList) 1.0 1.0 1.0
    Elevator.Elevator(int, int, long, GlobalController, Controller) 1.0 1.0 1.0
    Elevator.getBlock() 1.0 1.0 1.0
    Elevator.getCtrl() 1.0 1.0 1.0
    Elevator.getDirection() 1.0 1.0 1.0
    Elevator.getEleId() 1.0 1.0 1.0
    Elevator.getFloor() 1.0 1.0 1.0
    Elevator.inDir(PersonRequest) 1.0 1.0 1.0
    Elevator.move(long) 1.0 1.0 1.0
    Elevator.openAndClose() 1.0 5.0 5.0
    Elevator.setBlock(char) 1.0 1.0 1.0
    Elevator.setCtrlKey(String) 1.0 1.0 1.0
    Elevator.setDirection(int) 1.0 1.0 1.0
    Elevator.setFloor(int) 1.0 1.0 1.0
    Elevator.specialWait() 1.0 1.0 1.0
    Elevator.takeIn(String) 1.0 13.0 13.0
    Elevator.takeOff(String) 1.0 4.0 4.0
    Elevator.waitInDir(PersonRequest) 1.0 1.0 1.0
    ElevatorP.ElevatorP(int, int, int, long, int, GlobalController, Controller) 1.0 1.0 1.0
    ElevatorP.canCarry(PersonRequest) 1.0 1.0 1.0
    ElevatorP.canStop() 1.0 1.0 1.0
    ElevatorP.isFrom(PersonRequest) 1.0 1.0 1.0
    ElevatorP.isTo(PersonRequest) 1.0 1.0 1.0
    ElevatorP.move(long) 1.0 4.0 4.0
    ElevatorP.reqDir(PersonRequest) 1.0 1.0 3.0
    ElevatorP.waitDir(PersonRequest) 1.0 1.0 3.0
    ElevatorV.ElevatorV(char, int, int, long, GlobalController, Controller) 1.0 1.0 1.0
    ElevatorV.canCarry(PersonRequest) 1.0 1.0 1.0
    ElevatorV.canStop() 1.0 1.0 1.0
    ElevatorV.isFrom(PersonRequest) 1.0 1.0 1.0
    ElevatorV.isTo(PersonRequest) 1.0 1.0 1.0
    ElevatorV.reqDir(PersonRequest) 1.0 1.0 1.0
    ElevatorV.waitDir(PersonRequest) 1.0 1.0 1.0
    GlobalController.GlobalController() 1.0 1.0 1.0
    GlobalController.addController(ElevatorRequest) 1.0 2.0 2.0
    GlobalController.addElevator(ElevatorRequest) 1.0 3.0 3.0
    GlobalController.addElevatorP(ElevatorRequest) 1.0 2.0 2.0
    GlobalController.addElevatorV(ElevatorRequest) 1.0 2.0 2.0
    GlobalController.addRequest(PersonRequest) 1.0 5.0 5.0
    GlobalController.infoInputKilled() 1.0 2.0 2.0
    GlobalController.initControllers() 1.0 2.0 2.0
    GlobalController.initElevators() 1.0 2.0 2.0
    GlobalController.withoutTransfers() 1.0 1.0 1.0
    InputHandler.InputHandler(ElevatorInput) 1.0 1.0 1.0
    OutputHandler.initStartTimestamp() 1.0 1.0 1.0
    OutputHandler.println(String) 1.0 1.0 1.0
    Unit2.main(String[]) 1.0 1.0 1.0
    ElevatorP.specialWait() 3.0 2.0 3.0
    GlobalController.addNextRequest(String, PersonRequest) 3.0 4.0 5.0
    InputHandler.run() 3.0 6.0 6.0
    ElevatorV.move(long) 4.0 4.0 4.0
    Elevator.run() 5.0 13.0 15.0
    GlobalController.findTranFloor(char, char, int, int) 5.0 3.0 6.0
    Elevator.ifOpen() 6.0 12.0 14.0
    Total 82.0 131.0 144.0
    Average 1.37 2.18 2.40
协作图

附:度量分析条目解释
  • OC:类的非抽象方法圈复杂度,继承类不计入
  • WMC:类的总圈复杂度
  • ev(G):非抽象方法的基本复杂度,用以衡量一个方法的控制流结构缺陷,范围是 [1, v(G)]
  • iv(G):方法的设计复杂度,用以衡量方法控制流与其他方法之间的耦合程度,范围是 [1, v(G)]
  • v(G):非抽象方法的圈复杂度,用以衡量每个方法中不同执行路径的数量

二、调度器设计

三、同步块与锁分析

本单元代码中的所有用到共享对象的部分,我都选择了使用 synchronized 加锁。主要用途如下:

  • 共享对象的类方法

    如果方法涉及到读写本类内属性的操作,给该方法上锁。

// Controller.java
// requests为类内属性
public synchronized void addRequest(PersonRequest pr) {
	requests.add(pr);
	this.notifyAll();
}
  • 线程对象中的同步块

    如果线程对象中涉及到连续读写共享对象,且上下文连接紧密,不可中断的操作,给该代码块上锁。

    设置同步块的大多数场景为:电梯对象遍历访问候乘表的所有请求。此时须保证遍历的全过程中候乘表不能被更改,否则将会出现线程不安全错误。

// ElevatorP.java
// getCtrl()返回共享对象
synchronized (getCtrl()) {
	for (PersonRequest x: getCtrl().getRequests()) {
		char from = x.getFromBuilding();
		char to = x.getToBuilding();
		if (((switchInfo >> (from - 'A')) & 1) +
			((switchInfo >> (to - 'A')) & 1) == 2) {
			return false;
		}
	}
}

在第一次作业中,我的共享对象全部是同一个类的实例,且共享对象之间不会有互相访问的情况。因此,用最粗暴的方法“只要涉及共享对象,全部上锁!”不会导致死锁。

从第二次作业开始,我将原来的生产-消费模式中的一级托盘重构为二级托盘。因此在实现时特别留意,防止两类共享对象肆意加锁导致的死锁。具体策略如下:

  • 可以锁住一级托盘访问二级托盘,二级托盘锁内不可访问一级托盘
// GlobalController.java
// 一级托盘:GlobalController,二级托盘:Controller
public synchronized void infoInputKilled() {
	this.inputAlive = false;
	for (Controller ctrl : controllers.values()) {
		synchronized (ctrl) {
 			ctrl.setInputAlive(false);
 			ctrl.notifyAll();
		}
 	}
}
  • 线程对象中,二级托盘同步块内避免调用其他共享对象的(加锁)方法、避免二次设置同步块
// Elevator.java
// gctrl为一级托盘对象,ctrl为二级托盘对象
boolean transEnd = gctrl.withoutTransfers();	// 在二级托盘同步块外调用一级托盘
synchronized (ctrl) {
	if ((ctrl.getRequests().isEmpty() || specialWait()) && direction == 0) {
		if (ctrl.isInputAlive() || !transEnd) {		// *
			...
        } else { return; }
	} else {
        ...
    }
}

由于我的同步块内基本上都是读写并举,改用读写锁的轻量化意义不大,所以全程只用了 synchronized 的方式上锁。

标签:OO,2.0,1.0,BUAA,Elevator,Controller,GlobalController,PersonRequest,Unit
来源: https://www.cnblogs.com/ChorlingLau/p/16197054.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有