总结lab6 ADT设计方案
-
- ADT设计方案
设计了哪些ADT、各自的作用、属性、方法;
一. Monkey
猴子类。继承Thread。
作用:每个猴子为一个线程,对于一只猴子在某时刻选择并爬上某个梯子,意味着它跳到第 1 个踏板上。猴子一旦上了某个梯子,就不能在中途跳到别的梯子上。当猴子跳出梯子,该线程结束。
fields:
private final int id; //num of monkey
private final String direction; //initially L or R
private int v; //speed
private int position = 0; //position in the ladder
private final int produceTimer; //timer to record produceTime
private int now; //timer to record the elapsed time
private boolean finished = false; //Whether it has passed the ladder
private Strategy ladderStratrgy; //strategy of choosing ladder
private Ladder ladder = null; //Ladder being used
方法:
// getters方法
// setters方法
主要的方法是重写run
1. 方法开始要根据策略选择梯子,传入的参数是猴子的direction,返回的是选到的梯子对象或null,如果返回为null,则线程sleep 1秒,while循环中下一秒继续选择梯子。
ladder = this.ladderStratrgy.chooseLadder(this.direction); //选梯子
2. 如果选到了不为null的梯子,调用Ladder类中的方法使猴子上梯子。
ladder.upLadder(this); //上梯子
3. 接下来又是一个while循环,判断的是猴子的状态finished是否为true,while循环的内部调用Ladder.cross(this)使猴子不断在梯子上移动,如果猴子的位置超出了梯子的长度,则finished变为true,且猴子下梯子。
二. Ladder
梯子类。
作用:梯子提供了猴子过桥的工具,其中包含了猴子选踏板、上梯子、过梯子、下梯子等方法。
fileds:
private int leftCrossing = 0; //monkeys from the left direction
private int rightCrossing = 0; //monkeys from the right direction
private int[] pedals = new int[CrossingSimulator.h + 10]; //pedals free or occupied
private final int id; //number of ladder
方法:
//getters
//setters
其中getters和setters都是被synchronized修饰的方法,这些方法为同步方法,synchronized作用的范围是整个方法,作用的对象是调用这个方法的Ladder对象;
public synchronized void upLadder(Monkey monkey)
该方法为猴子上梯子,synchronized修饰的同步方法,如果猴子的方向是L->R,则leftCrossing++,否则rightCrossing++。
public void cross(Monkey monkey)
该方法为猴子过梯子,针对这个方法,为了提高线程并行的效率,未使用synchronized方法修饰方法,而是修饰一个代码块,为同步语句块,其作用的范围是大括号{}括起来的代码,加锁的对象还是ladder。
先根据梯子上的占用情况选择踏板,将猴子的原位置设置为0,将猴子的新位置设置为1,并且猴子内部的position也更新。执行这步需要1s,因此需要将猴子现在的时钟加1s。
public synchronized void exit(Monkey monkey)
该方法为猴子下梯子,synchronized修饰的同步方法,如果猴子的方向是L->R,则leftCrossing--,否则rightCrossing--。梯子某个方向的猴子数量减一,并且猴子离开梯子前的最后一块踏板设置为0。
private int choosePedal(Monkey monkey)
猴子选择踏板。先获得猴子此时的位置,和其速度(最大可能移动距离)。
我们需要讨论猴子的最大可能移动的位置是否会超出梯子,如果不会超出梯子,再讨论移动范围内前面是否有猴子,如果没有,返回最远可能踏板,如果有,返回没有猴子的最近踏板,并且猴子速度需要降低。如果会超出梯子,再讨论梯子前面是否有猴子,如果有,则返回梯子最远距离,如果没有,返回最远可能踏板,并且猴子速度需要降低。
方法的内部,多重if else讨论的语句块中需要对pedals进行加锁。
三. CrossingSimulator
过河模拟器。
作用:实现与用户交互,读入用户输入的参数或v3中的文件,获得实验中monkey和ladder的参数。
fields:
public static final int h = 20; //length of ladders
public static int n; //quantity of ladders
public static ArrayList<Monkey> monkeyList = new ArrayList<Monkey>(); //list to store monkeys
public static ArrayList<Ladder> ladderList = new ArrayList<Ladder>(); //list to store ladders
public static final Logger log = Logger.getLogger(CrossingSimulator.class.getSimpleName()); //logging
public static double extraTime = 0; //time spent on GUI and log
方法:
main()
读入用户输入猴子生成器需要的参数
写日志,新建一个猴子生成器,在其produce方法中传入参数。
四. MonkeyGenerator
猴子生成器。
1. 在猴子生成器MonkeyGenerator中只有一个方法,
public void produce(int n, int h, int t, int monkeyQuantity, int k, int mv , int s)
其中方法的参数由用户输入后传入,分别为梯子数n,阶梯数h(固定为20),产生猴子间隔秒数t,猴子总数,一次产生的猴子数量,猴子的最大速度,策略(猴子过河模拟器v2中使用)。
2. 得到这些参数后,我们需要随机生成猴子的信息,猴子的ID就在根据猴子对象产生的顺序编号。其他的信息,把猴子的两个方向放到一个集合中,把三种策略的对象放在一个集合中,然后以如下的形式产生随机数,即可在集合中随机获得属性。
Random random = new Random();
int rd = random.nextInt(2);
3. 至于产生猴子的时间和数量,则根据传入的参数t、k和monkeyQuantity,使用一个两重循环即可。另外,如果monkeyQuantity/????不为整数,则最后一次产生的猴子个数为monkeyQuantity%????。
给出每个ADT的specification;
Ladder:对于梯子类,还需要保证线程安全
Monkey:
CrossingSimulator: