其他分享
首页 > 其他分享> > OO第二单元总结

OO第二单元总结

作者:互联网

同步块的设置和锁的选择

在三次的作业中,我都是选择共享变量waitQueue作为锁。对于需要读取或写waitQueue的语句块,我们需要在其外面加锁。以下以第一次作业为例进行分析。

例1:

synchronized (waitQueue) {
                if (end && passenger.isEmpty() && waitQueue.isEmpty()) {
                    break;
                } else if (passenger.isEmpty() && waitQueue.isEmpty()) {
                    try {
                        waitQueue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

在上面的代码中,由于需要判断waitQueue是否为空,所以需要加锁避免出错。

例2:

PersonRequest request = elevatorInput.nextPersonRequest();
            if (request == null) {
                break;
            } else {
                synchronized (waitQueue) {
                    waitQueue.add(request);
                    waitQueue.notifyAll();
                }
            }

在上面的代码中,由于需要向waitQueue中添加请求所以需要加锁,且由于例1waitQueue在为空时wait,所以在此还需要对waitQueue进行notifyAll以唤醒锁。

调度器设计

第一次作业只有一个电梯,故未设计调度器。第二次与第三次作业的调度器结构类似,故以第三次作业为例。

由于程序体量较小,故调度器即为数据输入线程,由数据输入线程对电梯线程进行调度。电梯调度时使用共有的等待队列waitQueue,由电梯线程进行竞争性运行。

交互过程:调度器一开始调用初始的三部电梯,之后在处理请求时,若为乘客请求,则将其加至waitQueue中,若为电梯请求,则新实例化一个电梯线程并启动。

第三次作业架构设计的可拓展性分析

在第三次作业中,依旧使用和前两次类似的电梯运行策略(竞争性运行),功能与性能取得了较好的平衡。

基于度量分析程序设计结构

Complexity Metrics

method ev(G) iv(G) v(G)
Elevator.run() 6.0 19.0 21.0
Strategy.moveTo(ArrayList,ArrayList,String,String) 2.0 11.0 15.0
Elevator.getIn(Ask) 6.0 15.0 17.0
Elevator.move(Ask,int) 7.0 7.0 9.0
Strategy.hasAskWait(ArrayList,String) 5.0 8.0 13.0
WaitQueue.run() 3.0 9.0 10.0
Strategy.fit(Ask,String) 4.0 7.0 12.0
Elevator.getOff(ArrayList) 1.0 10.0 11.0
Elevator.down() 1.0 5.0 5.0
Elevator.floorOutAndIn(Ask) 1.0 6.0 6.0
Elevator.outAndIn(Ask) 1.0 5.0 6.0
Elevator.up() 1.0 5.0 5.0
DebugInput.run() 1.0 2.0 4.0
Elevator.Elevator(WaitQueue,ArrayList,ArrayList,int,String) 1.0 2.0 3.0
WaitQueue.isEmptyPassenger() 3.0 2.0 3.0
Elevator.close() 1.0 2.0 2.0
Elevator.open() 1.0 2.0 2.0
Ask.Ask(int,int,int) 1.0 1.0 1.0
Ask.getFromFloor() 1.0 1.0 1.0
Ask.getId() 1.0 1.0 1.0
Ask.getToFloor() 1.0 1.0 1.0
Ask.setFromFloor(int) 1.0 1.0 1.0
DebugInput.DebugInput(OutputStream) 1.0 1.0 1.0
Elevator.getPassenger() 1.0 1.0 1.0
Elevator.setEnd(boolean) 1.0 1.0 1.0
Elevator.setPattern(String) 1.0 1.0 1.0
Main.main(String[]) 1.0 1.0 1.0
WaitQueue.WaitQueue(ArrayList) 1.0 1.0 1.0
class OCavg OCmax WMC
Strategy 9.33 13.0 28.0
Elevator 4.07 11.0 57.0
WaitQueue 4.0 8.0 12.0
DebugInput 1.25 1.0 5.0
Ask 1.0 1.0 5.0
Main 1.0 1.0 1.0

分析上面数据,可知复杂度较大的方法为Elevator.run()、Elevator.getIn(PersonRequest)、Strategy.moveTo(ArrayList,ArrayList,String)。run()方法时由于需要调用大量elevator的其他方法,getIn()和moveTo()是因为判断嵌套多且条件复杂。

Dependency

Class Cyclic Dcy Dcy* Dpt Dpt*
Ask 0.0 0.0 0.0 4.0 4.0
DebugInput 0.0 0.0 0.0 1.0 3.0
Elevator 1.0 3.0 4.0 1.0 2.0
Main 0.0 2.0 5.0 0.0 0.0
Strategy 0.0 1.0 1.0 1.0 3.0
WaitQueue 1.0 3.0 4.0 2.0 2.0

第三次作业出现了相互依赖的情况,为Elevator类与WaitQueue类。

可拓展性

SRP--单一职责原则

OCP--开放-封闭原则

LSP--替换原则

DIP--依赖倒置原则

ISP--接口隔离原则

类图

image

时序图

image

分析自己程序的bug

第一次和第二次作业都没有出现bug,第三次作业出现了bug。

第三次作业强测中有两个相同类型的点没过,是功能性错误。

如何有效发现别人的bug

在互测环节,由于时间关系和多线程的不可复现性,并没有发现别人的bug。寻找bug的策略如下。

心得体会

通过本单元的三次作业,我对Java多线程编程有了一个初步的认识,并了解了一些简单的互斥访问与同步控制的方法。

在多线程编程中,通过线程安全的共享对象来完成线程间交互是十分清晰而简洁的方式。通过对象锁,可以使该对象在同一同步块内只能被一个线程访问,且不会被打断。再结合wait和notifyAll方法,可以避免轮询,高效利用CPU资源。

在设计中遵循SOLID原则及一些其他重要的设计原则也是十分重要的,这些原则保证了程序结构的清晰性和良好的可扩展性。在本单元作业中,部分设计原则未能体现甚至有所违背,在今后的编程中会多加注意。

期待下一单元的主题。

标签:OO,总结,1.0,Elevator,电梯,Ask,2.0,waitQueue,单元
来源: https://www.cnblogs.com/zhl-hhh/p/14696865.html