软件构造第十章学习笔记

标题 软件构造第十章学习笔记

感想:目前软件构造里感觉学的很舒服的一张了,就是博客写的难受
在这里插入图片描述
在这里插入图片描述
多线程
——线程与进程
——进程一般被抽象成虚拟机,而进程则被抽象成一个虚拟处理器。
关系:一个进程可以对应多个线程,线程拥有自己的堆栈和局部变量,但是共享内存空间,而进程拥有私有的内存空间。(除非有特殊机制进程不共享内存)
我们kill一个线程是不安全的,但是kill一个进程是安全的。
在这里插入图片描述

——站在程序员角度,main线程是开始线程,可以通过它创建其他的线程:
较为少用的方法:创建Thread类的子类
在这里插入图片描述
常用的方法:实现Runnable接口,并使用thread构造器
在这里插入图片描述
(所有的Thread都实现了Runnable接口,Thread类型本身有实现其接口,虽然他的run()什么都不做)

——匿名类与比较器:
比较器:在这里插入图片描述
可以通过比较器构造一个可排序的集合:(我们构造的集合会按照比较器的原则进行排序)
在这里插入图片描述
而,我们不一定非要先声明一个比较器然后构造:
在这里插入图片描述
——使用匿名类的优缺点:
优点:1.明确了使用范围,这里生成的对象只在这里使用 2.读者不需要寻找定义,生成之后即使用
缺点:1.这样生成的对象不可复用 2.因为在代码中进行产生会导致代码过长而影响理解
——竞争行为:
-当结果的正确性(后置条件和不变量)取决于事件的相对时序时
-多个线程共享同一个可变变量,而不协调它们在做什么。
-这是不安全的,因为程序的正确性可能取决于低级操作的时序事故。
——仅仅通过信息交互并不能避免竞争的问题
——happens-before relationship:
前一个事件的结果可以被后续的事件获取,即使出于优化的目的,实际运行中并不是按照指定顺序执行,在Java中,采用happened-before机制,保证了语句A对内存的写入对语句B是可见的,也就是在B开始读数据之前,A已经完成了数据的写入
——对于多线程程序来说很难DEBUG:
-很难让它们以同样的方式发生两次。
-指令或消息的交错取决于受环境强烈影响的事件的相对时序。
-延迟是由其他正在运行的程序、其他网络流量、操作系统调度决策、处理器时钟速度变化等造成的。
-每次运行包含竞争条件的程序时,都可能会得到不同的
行为。
——线程安全:
数据类型或静态方法在多线程中执行时,无论如何执行,不需调
用者做额外的协作,仍然能够行为正确,则称为线程安全的:
1.行为正确:行为正确意味着满足规格说明和保持不变性
2.不管线程是如何执行的:意味着线程可能在多个处理器上,或者在同一处理器上进行时间分片;
3.不需调用者做额外的协作:不能在前置条件中对调用者增加时间性要求
——四种线程安全的方式:
1.限制可变变量的共享
全局静态变量在被多个线程调用时可能会产生多个实例,所以,在并发程序中,尽量不要使用全局静态变量
2.仅共享不可变的变量:
这种方法仅仅保证了final的对象是不可变的,在使用这种方法时,需要保证变量所指向的其他变量也要是不变的。
而且仅仅对于用户不可变的的变量是不安全的,对象有可以改变的抽象方法,需要用锁来保证自身的安全。
但是,如果程序满足:没有改变数据的操作,所有的字段均为private 和 final,没有表示泄露,表示中的任何可变对象都不能变化。则程序一定是安全的。
3.将共享数据封装在线程安全的数据类型里
注意ArrayList,HashSet,HashMap,都是线程不安全的。线程安全的数据类型要保证他的操作都是原子操作。
原子方法:动作的内部操作不会同其他操作交叉,不会产生部分完成的情况。(注意:原子操作还不足以保证线程安全,因为即使原子操作本身是安全的,在多个原子操作之间仍然可能是产生竞争)
注意:Collections类型里包括了所有的线程安全的封装,其不提供public class, 只提供静态工厂方法
在这里插入图片描述
包装的实现是将所有的实际工作委托给指定的容器,但在容器
的基础上添加额外的功能。注意包装之后的对象,例如:新的HashMap只传递给synchronizedMap,并且永远不会存储
在其他地方,因为底层的容器仍然是可变的,引用它的代码可以
规避不变性,失去了包装的意义。
迭代器即使是在经过包装之后的类型中也是不安全的,如果一定要使用迭代器,则要在进行时获得它的锁。
在这里插入图片描述
4.使用同步机制来防止线程同时使用变量

——锁定机制
Java将锁定机制作为内置语言特性提供,每个类及其所有对象实例都有一个锁。
——同步语句
在这里插入图片描述
注意:锁只能确保与其他请求获取相同对象锁的线程互斥访问,如果其他线程没有使用synchronized(obj)或者利用了不同的锁,则同步会失效,需要仔细检查和设计同步块和同步方法。
——volatile类型
使用volatile变量可以降低内存一致性错误的风险
——死锁可能涉及两个以上的模块:
线程间的依赖关系环是出现死锁的信号
在这里插入图片描述
防止死锁的一种方法是对需要同时获取的锁进行排序,并确保所有代码按照该顺序获取锁定。
但是这样的情况有很多的缺点:(1)需要知道所有的锁,无法模块化。(2)在获得第一个锁之前,准确地知道它需要哪些锁可能是困难的或者不可能的。
——饥饿:
描述了线程无法获得对共享资源的访问,而无法取得进展的情况
——活锁:
类似于,相向而行,同时让路
线程调度方法:
——sleep():让当前线程暂停指定时间的执行,期间不参与CPU的调度,不释放所拥有的监视器资源(锁)
——Join():用于保持当前正在运行的线程的执行,直到该线程死亡(执行完毕),才能继续执行后续线程
在这里插入图片描述
o.wait(): release lock on o, enter o‘s wait queue and wait 释放拥有对象o锁的线程的拥有权,使线程进入等待状态
o.notify(): wake up one thread in o‘s wait queue 唤醒对象o锁的等待队列上的单个线程
o.notifyAll(): wake up all threads in o‘s wait queue唤醒对象o锁的等待队列上的所有线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值