【软件构造】软件构造复习总结4-第六、七章部分

【软件构造】软件构造复习总结4-第六、七章部分

第六章
一、健壮性与正确性
二、错误与异常处理
1.运行时异常:由程序员在代码里处理不当造成,如空指针,数组溢出等异常。
2.其他异常:由外部原因造成
3.Checked Exceptions:编译器可帮助检查你的程序是否已抛出或处理了可能的异常。
需要从Exception派生出子类型。必须捕获或传递。
4.Unchecked Exceptions:Errors and Runtime Exceptions是Unchecked Exceptions,不需要在编译的时候用try…catch等机制处理,编译时编译器也不会提醒。
5.方法 throws 异常。
6.如果客户端可以通过其他的方法恢复异常,那么采用checked exception; 如果客户端对出现的这种异常无能为力,那么采用unchecked exception
7.错误可预 料,但无法预防,但可以有手段从中恢复,此时使用checked exception。
8.Checked Exceptions在spec中要标出,如:
在这里插入图片描述
9.如果子类型中override了父类型中的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型更宽泛;子类型方法可以抛出更具体的异常,也可以不抛出任何异常;
10.抛出一个异常:throw Exception
11.创建一个新的checked异常类:
在这里插入图片描述
12.finally: 如果异常发生前曾申请过某 些资源,那么异常发生后这些资源要被恰当的清理,如:
在这里插入图片描述
输入流需要关闭。
三、断言与防御式编程
1.断言:在开发阶段的代码中嵌入,检验某些“假设”是否成立。若成立,表明程序运行正常,否则表明存在错误。如:
在这里插入图片描述
如果发生错误,“:”后的内容会显示到控制台。
2.防御式编程:
在这里插入图片描述
四、代码调试
1.git bisect:使用二进制搜索来查找项目历史记录中引入错误的提交•使用它时首先告诉它一个已知包含错误的“bad”提交,以及一个“好的”提交,在引入bug之前就知道了。
2.Debugging tools:
在这里插入图片描述
Memory dump:硬盘上的一个文件,其中包含一个进程在特定时间内存中的内容的副本,当进程因某种内部错误或信号而中止时产生。当程序中止时,可以进行内存转储,以检查程序在崩溃时的状态。
日志:log(结合实验中的代码复习)不多赘述。

第七章
一、并发
1.两种常见的并发模型:共享内存和消息传递
2.共享内存:在内存中读写共享数据
3.消息传递:通过channel交换消息
4.进程和线程:
进程:正在运行程序的一个实例,拥有自己私有专用的内存空间,可理解成一台虚拟计算机,拥有独立环境和完整资源。
进程间通过消息传递进行协作。进程间通常不共享内存。
线程:线程是正在运行程序的一个执行路径(一个进程可对应 多个线程),线程有自己的堆栈和局部变量,但是多个线程共享内存空间,可以抽象为虚拟处理器。
线程存在于进程中。进程内的线程共享内存。
5.两种方法创建线程:从Thread中派生子类;从Runnable接口构造Thread对象。
6.从Thread中派生子类:如:
在这里插入图片描述
7.从Runnable接口构造Thread对象:
在这里插入图片描述
线程启动:.start()。
8.通过时间分片,在多个进程/线程之间共享处理器
9.共享内存,线程可能出现问题:如存钱取钱,指令会被分成底层指令,会存在交叉导致出错:
在这里插入图片描述
10.Race Condition(竞争条件):程序的正确性(后置条件和不变性的满足)取决于并发计算A和B中事件的相对时间。
例:
在这里插入图片描述
AB方法同时运行。会有多种结果。
在这里插入图片描述
11.Thread.sleep(Time) 线程休眠,
t.interrupt() 向t线程发出中断信号
t.isInterrupted() 检查t线程是否在中断中
使用:
在这里插入图片描述
在休眠时收到中断信号会抛出异常,进入异常处理,线程终止。
另一种方案:
在这里插入图片描述
使用if(),如果收到异常中断的信号,抛出中断异常,不收到则一值while循环执行操作。
二、线程安全:
1.Confinement(禁闭):线程之间不共享mutable数据类型,同时避免使用全局变量。如:
在这里插入图片描述
每次compute都创建一个新的1和n,计算独立,各自计算自己的。
2.Immutability(不变性): 使用不可变数据类型和不可变引用,避免多线程之间的race condition。如果ADT中使用了beneficent mutation,必须要通过“加锁”机制来保证线程安全。
更强的不变性:没有改变数据的操作,rep都是private和final的,没有表示泄露,表示中的任何可变对象都不能变化,这样可以做到线程安全。
3.Using Threadsafe Data Types(使用线程安全的数据类型): 如果必须要用mutable的数据类型在多线程之间共享数据,要使用线程安全的数据类型。
集合类都是线程不安全的:可以使用:
在这里插入图片描述
对它们的每一个操作调用,都以原子方式执行。
原子方式:动作的内部操作不会同其他操作交叉,不会产生部分完成的情况。
在使用synchronizedMap(hashMap)之后,不要再把参数hashMap共享给其他线程,不要保留别名,一定要彻底销毁。
即使在线程安全的集合类上,使用iterator 也是不安全的,解决办法:使用lock机制。
执行其上某个操作是threadsafe的,但如果多个操作放在一起,仍旧不安全,如:
在这里插入图片描述
三、锁与同步
1.锁机制:使用锁机制,获得对数据的独家mutation权,其他线程被阻塞,不得访问。
2.锁的两种操作:
A.获取锁:如果一个线程试图获取另一个线程当前拥有的锁,它会阻塞,直到另一个线程释放锁为止。一次最多只能有一个线程拥有锁。
B.释放锁:允许另一个线程获得它的所有权。
3.Lock:
在这里插入图片描述在这里插入图片描述

要互斥,必须使用同一个lock进行保护。
4.Monitor模式:ADT所有方法都是互斥访问,如:
在这里插入图片描述
也可以写成:
在这里插入图片描述
5.对于synchronized方法,多线程不允许有交叉,即按原子的串行方式执行。
Synchronized会给程序带来极大影响,除非必要,否则不要用。避免在方法spec中加synchronized,而是在方法代码内部更加精细的区分哪些代码行可能有threadsafe风险,为其加锁
6.任何共享的mutable变量/对象必须被lock所保护, 涉及到多个mutable变量的时候,它们必须被同一个lock所保护,如:
在这里插入图片描述
7.高级一些的原子操作:同步各个小调用方法,确保了方法间调用的互不 干扰,实现了findReplace的原子性
在这里插入图片描述
8.死锁:两个线程互相等待对方释放lock,形成死锁。
9.解决方案1:对需要同时获取的锁进行排序,并确保所有代码都按该顺序获取锁。
10.解决方案2:使用粗糙的锁-使用一个锁来保护许多对象实例,甚至是程序的整个子系统。缺点:对性能造成严重的影响。–如果您用一个锁来保护大量可变数据,那么您就放弃了并发访问这些数据的能力。–在最坏的情况下,只有一个锁来保护所有东西,您的程序可能基本上是顺序的。
11.保护块:某些条件未得到满足,所以一直在空循环检测,直到条件被满足。但是极大的浪费。
在这里插入图片描述
o.wait(): 释放拥有对象o 锁的线程的拥有权,使线程进入等待状态。使object所处的当前线程进入阻塞/等待状态,直到其他线程调用该对象的notify()操作
o.notify(): 唤醒对象o锁的等待队列上的单个线程
o.notifyAll(): 唤醒对象o锁的等待队列上的所有线程

/***********************************************************************************/
以上即为软件构造复习总结4-第六、七章部分。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值