LAB6

目录

 

1 实验目标概述··· 1

2 实验环境配置··· 1

3 实验过程··· 1

3.1 ADT设计方案··· 1

3.2 Monkey线程的run()的执行流程图··· 1

3.3 至少两种“梯子选择”策略的设计与实现方案··· 2

3.3.1 策略1· 2

3.3.2 策略2· 2

3.3.3 策略3(可选)··· 2

3.4 “猴子生成器”猴子生成器··· 2

3.5 如何确保threadsafe?··· 2

3.6 系统吞吐率和公平性的度量方案··· 2

3.7 输出方案设计··· 2

3.8 猴子过河模拟器v1· 2

3.8.1 参数如何初始化··· 2

3.8.2 使用Strategy模式为每只猴子随机选择决策策略··· 2

3.9 猴子过河模拟器v2· 2

3.9.1 对比分析:固定其他参数,选择不同的决策策略··· 3

3.9.2 对比分析:变化某个参数,固定其他参数··· 3

3.9.3 分析:吞吐率是否与各参数/决策策略有相关性?··· 3

3.9.4 压力测试结果与分析··· 3

4 实验进度记录··· 3

5 实验过程中遇到的困难与解决途径··· 3

6 实验过程中收获的经验、教训、感想··· 4

6.1 实验过程中收获的经验和教训··· 4

6.2 针对以下方面的感受··· 4

 

 

 

1 实验目标概述

 

2 实验环境配置

简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。

特别是要记录配置过程中遇到的问题和困难,以及如何解决的。

本实验不需要特殊实验环境的配置。

在这里给出你的GitHub Lab6仓库的URL地址(Lab6-学号)。

3 实验过程

3.1 ADT设计方案

Rung-踏板:

域名

作用

rungs_Monkey

踏板所处的位置(从左到右)

 

方法名

作用

getRungs_Monkey

获得踏板的位置

setRungs_Monkey

设定踏板的位置

 

Specification:

AF:从左到右或者从右到左

RI:TRUE

Rep Explosure:没有泄露操作

Thead Sfety:接口,线程安全

 

 

Ladder-梯子:

作用

Id

梯子的编号

List<Rung>  rungs

梯子上的踏板

 

方法

作用

Public Rung getRungL2R(int rungIndex)

获得从左到右数第rungIndex个踏板

Public Rung getRungR2L(int rungIndex)

获得从右到左数第rungIndex个踏板

Public int getRungLength()

获得梯子上踏板的总数

Pubic int getLadderIndex()

获得当前梯子的编号

Specification:

AF:编号和踏板

RI:TRUE

Rep Explosure:没有泄露操作,get得到Rungs为不可变类型

Thead Sfety:不可变,线程安全

 

 

Monkey-猴子:

域名

作用

List<CrossriverStrategy> crossriverStrategies

该猴子可以使用的过河策略

Int id

猴子id

Int vel

猴子过河速度

MonkeyState state

猴子状态

猴子生成器 generator

保留的猴子生成器的引用

 

方法

作用

Pubic void findLadder

根据策略模式和版本要求选择梯子

Public void run()

线程运行程序

Specification:

AF:从左到右或者从右到左

RI:TRUE

Rep Explosure:没有泄露操作

Thead Sfety:有修改操作,注意线程安全

 

关系图:

猴子

梯子

踏板

 

 

 

 

 

 

3.2 Monkey线程的run()的执行流程图

 

3.3 至少两种“梯子选择”策略的设计与实现方案

3.3.1 策略1

 

3.3.2 策略2

 

3.4  “猴子生成器”猴子生成器

猴子的本质是一个线程,其具有三种状态(等待、过河中、已到达),在等待状态下,猴子根据某种策略,选择一架梯子;在过河过程中,猴子根据梯子上其他猴子的速度,向前跳若干个踏板,直到到达对岸为止。

创建一个定时任务,每隔指定时间之后执行一次。例如,我们要求是每3秒生成5个猴子,那么我们的计时器等到3秒之后,就会利用猴子生成器生成5个猴子。

对于每一次定时任务,按照要求生成k个猴子,对于每个猴子在范围内随机生成参数,将该猴子添加到猴子列表中,然后启动猴子的过河线程。

所有猴子线程共享的数据作为数据直接保存在猴子生成器中,在猴子的构造函数中需要将猴子生成器作为参数传入,这样就可以直接通过引用访问多线程共享的数据。

3.5 如何确保threadsafe?

梯子包含若干级踏板,而我们需要记录每个踏板上是否有猴子。这里的一种思路是使用一个锁,每次只能有一只猴子(线程)占有它。

多线程可能产生问题的地方在多个猴子可能同时想要进行选择梯子和猴子前进下一步的时候。

对于猴子上梯子操作,包括选梯子和上梯子两个步骤,这两个步骤必须作为一个原子操作,所以同一时刻只能安排有一只猴子上梯子,在本实验中,请求为梯子上锁。

对于猴子在梯子上行进的过程中,一个猴子移动包括根据形势做出判断、移动两个操作,根据猴子的判断和移动情况来决定是否为梯子上锁。

其实,只要一个猴子已经开始在梯子并且做出判断,我们完全没有必要请求梯子的锁,这并不会产生线程安全问题。

首先启动定时器,每t秒生成k只猴子,并等待这一生成过程完成;然后当猴子生成器累计产生了?只猴子之后,它停止产生新的猴子,等待所有线程执行结束。

3.6 系统吞吐率和公平性的度量方案

对于吞吐率、公平性的定义完全依照实验要求:

 

1.如何实现计算吞吐率和公平性?

在猴子生成器(储存线程共享数据)中添加一个到岸猴子计数器,当最后一个猴子达到对岸的时候计算吞吐率和公平性。

2.关于时间统计,每一个猴子都有一个计数器,过河线程每执行一次 他的时间都会续一秒 ,所有猴子过河的时间就是最大的出生前时间和出生后时间之和。所以程序吞吐率完全依赖于上梯子策略的选择。

3. 计算公平性的公式略微复杂,可以像(A,B), (A,C), (A,D), …, (B,C), (B,D)……这样按照猴子出生的字典序来进行计算。

 

3.7 输出方案设计

日志:

我们仍然按照LAB4的要求,使用LOG4J扩展包来生成日志,相关日志记录被存储在OUT文件夹中。

 

 

输出:

我们利用命令行进行输出,主要的输出的是每时每刻任意一个猴子的运动信息,只要它进行运动了,我们都会进行记录并且输出。

 

3.8 猴子过河模拟器v1

3.8.1 参数如何初始化

在命令根据提示输入指定参数来进行环境设定。

 

3.8.2 使用Strategy模式为每只猴子选择决策策略

这里使用了策略模式。

设计Interface接口函数,提供函数StrategyChoose,monkey按照既定策略选择一个可用的梯子,如果有,则跳上梯子的第一个踏板。

因为选梯子过程中涉及到访问线程共享数据,所以每一个实现类都需要在构造方法中传入MonkeyGenerator的引用。

 

3.9 猴子过河模拟器v2

在不同参数设置和不同“梯子选择”模式下的“吞吐率”和“公平性”实验结果及其对比分析。

3.9.1 对比分析:固定其他参数,选择不同的决策策略

固定参数为n = 5 , h = 10 , t = 2 , k = 2, N = 10 ,  MV = 3.

实验结果为:

策略1:

 

策略2:

 

 

3.9.2 对比分析:变化某个参数,固定其他参数

1.桥的数目对过桥速度的影响:

 

 

2.桥的长度对过桥速度的影响:

 

 

3. 最快速度对过桥速度的影响:

 

 

3.9.3 分析:吞吐率是否与各参数/决策策略有相关性?

(1)随着梯子数目n的增加,吞吐率变化不大。对于公平性,规律类似。说明三种策略对于增加梯子的利用效率不高。与具体算法策略关系不大。

(2)随着梯子长度的增加,吞吐率总体降低,公平性总体提高。爬梯子所用时间太长。与具体算法策略关系不大。

(3)随着最大速度的提高,吞吐率整体上升,公平性规律不明显。速度提高了,自然总体跑得快了。算法比较总体规律不明显。

 

3.9.4 压力测试结果与分析

(1)猴子数目很多

 

(2)梯子很长

 

结论:

大数据情况下,策略选择不够优化,因此吞吐率低,但公平性略好。

3.10 猴子过河模拟器v3

针对教师提供的三个文本文件,分别进行多次模拟,记录模拟结果。

 

吞吐率

公平性

1.txt

 

 

第1次模拟

2.22

0.56

第2次模拟

2.55

0.81

第3次模拟

2.33

0.78

第4次模拟

2.72

0.51

第5次模拟

2.26

0.76

第6次模拟

2.51

0.8

第7次模拟

2.28

0.87

第8次模拟

2.11

0.84

第9次模拟

2.15

0.61

第10次模拟

2.24

0.51

平均值

2.337

0.705

2.txt

 

 

第1次模拟

4.84

0.55

第2次模拟

4.88

0.62

第3次模拟

4.9

0.46

第4次模拟

4.98

0.55

第5次模拟

4.43

0.61

第6次模拟

5.27

0.49

第7次模拟

5.33

0.58

第8次模拟

5.34

0.56

第9次模拟

5.19

0.57

第10次模拟

4.66

0.65

平均值

4.982

0.564

3.txt

 

 

第1次模拟

1.11

0.57

第2次模拟

1.57

0.27

第3次模拟

1.02

0.62

第4次模拟

1.09

0.34

第5次模拟

1.28

0.84

第6次模拟

1.18

0.25

第7次模拟

0.94

0.93

第8次模拟

1.48

0.48

第9次模拟

1.37

0.2

第10次模拟

0.65

0.4

平均值

1.169

0.49

 

4 实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

日期

时间段

计划任务

实际完成情况

6/14

8:30-23:30

完成V1-V2

完成

6/15

8:00-23:00

完成V3

完成

6/16

10:30-20:00

完成报告

完成

 

5 实验过程中遇到的困难与解决途径

遇到的难点

解决途径

构造线程的时候极容易出现BUG

网上搜索

运行结果不令人满意

逐步调试

6 实验过程中收获的经验、教训、感想

6.1 实验过程中收获的经验和教训

(1)   事实上,Java的多线程机制本身也是一种封装:它将那些系统调用隐藏起来,呈现给我们一种统一的、易用的函数接口。

(2)   尽管如此,想写好多线程程序也是相当不易的。对共享数据的访问、死锁和线程间同步,是多线程的三大难题。

 

6.2 针对以下方面的感受

(3)   多线程程序比单线程程序复杂在哪里?你是否能体验到多线程程序在性能方面的改善?

时间上有大幅度提升

(4)   你采用了什么设计决策来保证threadsafe?如何做到在threadsafe和性能之间很好的折中?

尽量减少锁的范围

(5)   你在完成本实验过程中是否遇到过线程不安全的情况?你是如何改进的?

遇到过,逐步改善线程条件

(6)   关于本实验的工作量、难度、deadline。

适中

(7)   到此为止你对《软件构造》课程的意见和建议。

是一门非常有用的课,但是实验难度有点大,比较耗费时间,建议适当调整。

 

转载于:https://www.cnblogs.com/richardodliu/p/11061681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值