2020.05.29软件构造听课笔记

锁与同步:
线程安全不应该依赖于偶然

前三种策略的核心思想:
避免共享→即使共享,也只能读/不可写→即使可写,共享的可写数据应自己具备在多线程之间协调的能力,即使“使用线程安全的mutable ADT”

缺陷:不能用全局rep共享数据→只能“读”共享数据,不能写→可以共享“读写”,但只有单一方法是安全的,多个方法调用就不安全了

很多时候,无法满足上述三个条件→要读写共享数据,且线程中的读写操作复杂
程序员来负责多线程之间对mutable数据的共享操作,通过“同步”策略,避免多线程同时访问数据

使用锁的机制,获得对数据的独家mutation权,其他线程被阻塞,不得访问

Lock是Java语言提供的内嵌机制
每个object都有相关联的lock

拥有lock的线程可独占式的执行该部分代码

Lock用来保护共享数据
注意:要互斥,必须使用同一个lock进行保护

错误:拥有对象的锁会自动阻止其他线程访问同步区域
锁只能确保与其他请求获取相同对象锁的线程互斥访问,如果其他线程没有使用synchronized(obj)或者利用了不同的锁,则同步会失效,需要仔细检查和设计同步块和同步方法

Monitor Pattern(监视器模式):
用ADT自己做lock
ADT的一个实例(对象)中所有方法都是互斥访问的

读和写要受到同样的重视,避免返回处于部分修改状态的rep值

当线程调用同步方法时,他会自动获取该方法所在对象的内部锁,并在方法返回时释放他,即使返回时有未捕获的异常造成的。
同一对象上的同步方法的两次调用不会有交叉现象

当一个线程在执行一个对象的同步方法时,所有其他线程如果调用同一对象的同步方法块,则会挂起执行,直到第一个线程针对此对象的操作完成
当一个同步方法退出时,它会自动建立一个与之后调用同一个对象的同步方法的happens-before关系,这保证对象状态的更改对所有线程都是可见的

前一个事件的结果可以被后续的事件获取(即使出于优化的目的,实际运行中并不是按照指定顺序执行)
在Java中,采用happened-before机制,保证了语句A对内存的写入对语句B是可见的,也就是在B开始读数据之前,A已经完成了数据的写入

Static Synchronized Methods:
由于静态方法与类关联,而不是对象,此时线程获取与该类关联的Class对象的内部锁
对类的静态字段的访问由于该类的任何实例的锁截然不同的锁来控制

同步机制给性能带来极大影响
除非必要,否则不要用。Java中很多mutable的类型都不是threadsafe就是这个原因

尽可能减少lock的范围
如果用synchronized(this)作为lock,意味着lock是对象本身,如果对象对客户端是可见的的(拥有引用),则线程安全机制是public的,可能会受到客户端的干扰

避免在方法spec中加synchronized,而是在方法代码内部更加精细的区分哪些代码行可能有threadsafe风险,为其加锁

要先去思考清楚到底lock谁,然后再synchronized(...)

任何共享的mutable变量/对象必须被lock保护
涉及到多个mutable变量的时候,他们必须被同一个lock所保护
在monitor pattern中,ADT所有方法都被同一个synchronized(this)所保护

死锁:多个线程竞争lock,相互等待对方释放lock

解决方法1:给锁排序
需要知道子系统/系统中所有的锁,无法模块化,紧耦合
有时需要经过计算后才能知道需要用到哪些锁

解决方法2:粗粒度的锁,用单个锁来同步多个对象实例/子系统
性能损失大
如果用一个锁
保护大量的可变数据,那么就放弃了同时访问这些数据的能力
在最糟糕的情况下,程序可能基
本上是顺序执行的,丧失了并发性

保护块:
某些语句块需要轮询一个条件,满足时才能放行
某些条件未得到满足,所以一直在空循环检测,直到条件满足,这是极大的浪费

o.wait()释放拥有对象o锁的线程的所有权,是线程进入等待队列中
o.notify()唤醒对象o锁的等待队列中的某个线程
o.notifyAll()唤醒对象o锁的等待队列中的所有线程

object.notify()随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态
被唤醒的线程不会马上进行,需要等待当前获得锁的线程释放锁,同时还需要同其他等待锁的线程进行公平竞争

被唤醒的资源会重新参与到锁的竞争中,获取后,从wiat位置继续执行

当wait()被调用时,线程释放锁并暂停执行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值