管理纵向移动的等待队列和横向移动的等待队列的两个类:Building与Floor。两者本质都是生产者-消费者模型中的Tray,属于线程间的共享对象,需要对各方法进行synchronized保护。
具体实现方面,两者都采用了以ArrayList<Person>为元素的二维数组。即:
private ArrayList<Person>[][] req;
以Building为例,二维数组的第一个下标代表楼层,第二个下标代表方向,数组元素ArrayList即为某层前往某方向的等待队列;
e.g. req[6][0]代表目前处于六层、想要下楼的等待队列;req[9][1]代表目前处于九层、想要上楼的等待队列
在类中实现了putReq(), takeReq()等方法
纵向移动的电梯与横向移动的电梯:Elevator与ConveyorBelt。两者本质都是生产者-消费者模型中的Consumer,是两类线程。它们有三个状态:
捎带策略与调度策略在后文有详细阐述
输入线程类:InputThread。本质是生产者-消费者模型中的Producer
没有显式的设置主请求与捎带请求。由于两个本质为Tray的类中对等待队列的方向作出了划分,电梯只会让与运行方向相同的队列中的人登上电梯。
当电梯有人时,状态处于0 or 1,每改变一层决定是否开关门,从而实现捎带。
当电梯内无人时,需要重新确定电梯的运行方向。此时以该层以上的平均每层的人数与该层以下的平均每层的人数作为重新确定电梯运行方向的衡量指标,即:
dir = ((downNum * 1.0 / (curFloor - 1)) > (upNum * 1.0 / (FLOOR - curFloor))) ? 0 : 1;
环形电梯类似,比较顺时针半圈与逆时针半圈的人数
自由竞争 大道至简
加入电梯做好初始化后直接start()线程
本质只有两处线程安全问题:
在本架构设计中,两处线程安全问题彼此独立、互不影响。