软件构造第10章

10.1并发

并发即同时进行计算
方式:
共享内存:在内存中读写共享数据
消息传递:通过channel交换消息
进程:拥有整台计算机的资源
多进程之间不共享内存
进程之间通过消息传递进行协作
JVM通常运行单一进程,但也可以创建新的进程。
进程=虚拟机;线程=虚拟CPU
Java线程
每个应用至少有一个线程即主线程,可以创建其他的线程
创建线程的方法:
1.从Thread类派生子类,实现run()方法(Thread类run方法内为空)
2.从Runnable接口构造Thread对象,实现run()方法
3.匿名方法
正确方法:使用start而不是run
在这里插入图片描述

able
• Comparable (and Comparator)
• Iterable (and Iterator)
• Observable (and Observer)
• Throwable
• Cloneable
• Runnable

3 Interleaving and Race Condition交错和竞争

3.1时间分片

单核每个时刻只能执行一个线程
多核CPU,进程/线程的数目也往往大于核的数目
在这里插入图片描述
通过时间分片,在多个进程/线程之间共享处理器
时间分片是由OS自动调度的

3.2线程间共享内存

原子操作
在这里插入图片描述
单行、单条语句都未必是原子的
在这里插入图片描述
• 很难测试和调试因为竞争条件导致的bug
因为interleaving的存在,导致很难复现bug
即海森堡bug,串行bug为玻尔bug
• 利用某些方法调用来主动影响线程之间的interleaving关系
1.线程的休眠Thread.sleep()
将某个线程休眠,意味着其他线程得到更多的执行机会
进入休眠的线程不会失去对现有monitor或锁的所有权
2.收发信号
t.interrupt() 在其他线程里向t发出中断信号
t.isInterrupted() 检查t是否已在中断状态中
在这里插入图片描述
当某个线程被中断后,一般来说应停止其run()中的执行,取决于程序员在run()中处理
Thread.yield()方法,线程告知调度器:我可以放弃CPU的占用权,从而可能引起调
度器唤醒其他线程。
Thread.join()让线程保持执行,直到其执行结束
在这里插入图片描述

10.2线程安全

如何设计threadsafe的ADT
线程之间的“竞争条件”:作用于同一个mutable数据上的多个线程,
彼此之间存在对该数据的访问竞争并导致interleaving,导致postcondition
可能被违反,这是不安全的。
四种方式:
1.Confinement 限制数据共享. 没有Rep
2.Immutability 共享不可变数据. immutable的rep
如果ADT中使用了beneficent mutation,必须要通过“加锁”机制来保证线程安全
保证线程安全,不可变需要更强的定义
在这里插入图片描述
3.Thread safe data type 共享线程安全的可变数据. mutable的

Thread safe Thread not safe
StringBuffer StringBuilder
List , Set , Map Collections.synchronizedMap(new HashMap<>());

此时使用iterator() 或者循环也是不安全的
执行其上某个操作是thread safe的,但如果多个操作放在一起,仍旧不安全

4.Synchronization 同步机制:通过锁的机制共享线程不安全的可变数据,变并行为串行.
lock:每个object都有相关联的lock

Object lock = new Object();

synchronized (lock) { // thread blocks here until lock is free
// now this thread has the lock
balance = balance + 1;
// exiting the block releases the lock
}

Monitor模式:ADT所有方法都是互斥访问
在这里插入图片描述

等价于加synchronized关键字,构造函数无需
在这里插入图片描述
对synchronized的方法,按原子的串行方式执行
原则:
任何共享的mutable变量/对象必须被lock所保护
涉及到多个mutable变量的时候,它们必须被同一个lock所保护
monitor pattern中,ADT所有方法都被同一个synchronized(this)所保护

4 liveness

活性并发应用程序在某时刻执行的能力
– Deadlock 死锁:
多个线程竞争lock,相互等待对方释放lock
– Starvation 饥饿:
因为其他线程lock时间太长,一个线程长时间无法获取其所需的资源访问权(lock),导致无法往下进行。
– Livelock 活锁:

5保护块

在这里插入图片描述
Object.wait():
使object所处的当前线程进入阻塞/等待状态,直到其他线程调用该对象的notify()操作
Object.notify() /notifyAll()
随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态

猜你喜欢

转载自blog.csdn.net/a1058420631/article/details/92166192