并发实战
2022-03-18 23:21:30 7 举报
AI智能生成
并发实战
作者其他创作
大纲/内容
①什么是状态共享
1、共享
①什么是状态可变
2、可变
①什么是状态变量
②有哪四种状态变量
3、状态
1)理解前提术语
①本质原因
②如何判断线程是否安全
1、出现线程安全问题
2、三种解决线程安全问题的思路
3、java中的几种同步机制
2)理解线程安全性
一、理解
第零节
1)复杂的定义
1、这些定义让人困惑的两个原因
2、如何定义线程安全,才不会困惑
2)困惑的定义
①什么是『正确性』
1、理解『正确性』
3)理解前提
1、简易版
2、完全版
3)正确的定义
一、定义
1、功能说明
2、代码举例
3、此 servlet 线程安全的原因
A、如何理解局部变量,不会产生线程安全性问题
①只有局部变量
A、如何理解无状态对象,没有共享状态?
②没有共享变量
③为什么说,多个线程访问同一个无状态对象,就好像访问不同的实例一样,也即好像没有访问共享的对象一样
4、无状态对象,线程安全的原因
1)因数分解 servlet
二、举例
第一节 线程安全性
一、新的需求
1)叙述
2)代码
1、起初
2、过程
3、最后
4、错误原因
3)可能的错误
二、解决方案
①概念
②特点
③解决思路
1、什么是『竞态条件』
2、什么时候会出现『竞态条件』
3、为什么竞态条件,会带来线程安全性问题
1)概念
①为什么『先检查后执行』类型是竞态条件中最常见的
②本质
现实生活中『先检查后执行』类型的竞态条件
延迟初始化中的『先检查后执行』类型的竞态条件
③举例(没有做思维导图,今后做)
1、『先检查后执行』类型竞态条件
2、『读取-修改-写入』类型竞态条件(没有做思维导图,今后做)
2)分类
执行时序、竞态条件与线程安全的关系
3)存在的问题
①思路叙述
A、为什么,要解决『竞态条件』问题,就要解决执行时序不确定的问题?而不是把多线程变为单线程?
B、使用什么方法,解决执行时序不正确的问题?
C、什么是正确的执行时序?
D、如何确保正确的执行时序
②思路解释
1、解决『竞态条件』引起的线程安全性问题的『思路』
①严谨地描述复合操作
②什么是复合操作?
A、方法一:加锁机制(下一节讲)
a、代码
b、解释
c、结论
B、方法二:使用一个现有的原子变量类
③如何定义复合操作
2、复合操作
4)解决方案
三、竞态条件
第二节 原子性
1)当前的原子变量类,使用情况?
①对象只有一个状态变量
②对象有多个状态变量,但是状态变量之间,没有联系,也即不变性条件,不会由多个变量共同来描述
1、原子变量可以满足需要的情况
①多个状态变量,共同描述不变性条件
2、原子变量不可以满足需要的情况
2)当前的原子变量类,存在的问题?
3)局限性
一、原子变量类的局限性
1)目的
1、思路
2、代码
① servlet 是线程不安全的
②UnsafeCachingFactorizer的不变性条件之一
③解释:为什么不满足不变性条件
④错误结果
⑤解决方案
3、存在的问题
2)带有缓存的因式分解 servlet,线程不安全的实现方式
3)疑问
二、带有缓存的因式分解servlet
1)java 如何实现原子性
①第一个部分——作为锁的对象引用
②第二个部分——作为由这个锁保护的代码块
2)同步代码块的两个部分
A、获得锁
B、释放锁
①何时获得锁,何时释放锁?
②如何获得内置锁?
A、特点
B、举例解释
③锁的作用?
3)锁
①思路
②特点:简单
③方法
④问题
⑤代码
4)『带有缓存的因式分解 servlet』线程安全的实现方式
三、内置锁
1)什么是重入?(内置锁是可重入的)
①变量
②过程
2)重入的一种实现方法
①叙述
②代码
A、两个同步方法
B、同一把锁
C、什么情况下,线程会请求一个『已经由自己持有的』锁
D、为什么,如果不能重入,就会出现死锁?
③解释
3)为什么需要『重入』这种功能?
四、重入
第三节 加锁机制
第四节 用锁来保护状态(笔记为做好,思维导图暂时不做)
1)第一阶段:不安全的 servlet
2)第二阶段:没有并发的 servlet
1、叙述
2、问题根本原因
3、可以实现功能——保证线程安全
4、代价很大
2、注意事项
3、同步只需要加在什么地方?
4)新的解决思路
①第一个同步代码块
②第二个同步代码块
③因数分解功能之外,引入了两个计数器
④同步块之外的代码
1、解释
5)新的代码
一、举什么例子说明『活跃性与性能』
第五节 活跃性与性能
第二章 线程安全性
1)保证原子性
2)保证内存可见性
一、关键字 synchronized 的两个作用
什么时候需要保证『原子性』
什么时候需要保证『内存可见性』
二、何时需要确保原子性,内存可见性
三、锁、同步块、阻塞的关系
1、在单线程环境中
2、在多线程环境中
1)单线程和多线程,对『内存写入操作』的『可见性』
一、概念
1、共享变量
2、主线程和读线程的功能
A、正确情况一
B、错误情况一
a、叙述
b、原因
c、解释——重排序的结果
d、什么是『重排序』
f、出现『重排序』的根本原因
C、错误情况二
①打印出0的原因
②主线程很长时间没有打印
D、几种结果的分析
3、可能的两种『不希望情况』
3)解释
二、举例 说明
1)什么时候,会产生失效数据?
3)失效数据带来的错误后果?
1、代码
2、不安全的原因
3、什么时候会出现『失效值问题』
4)非线程安全的可变整数类——Mutablelnteger
2、解释
5)线程安全的可变整数类——SynchronizedInteger
三、失效数据
1、含义
2、不重排序
3、不缓存(也即总会返回最新值)
1)如何确保可见性
2)volatile变量和sychronized同步块的区别
1、volatile变量对可见性的影响比volatile变量本身更为重要
2、如何使用
3、作用
4、『volatile变量』类比同步代码块的在使用方法上的比较
5、为什么,不建议过度依赖volatile变量提供的可见性
A、在多个线程进行修改时,一定不能出现竞态条件
B、单个线程进行修改时(一定不会出现竞态条件,你不需要确保原子性)
①不需要『确保原子性』的情况下
②不需要使用更高级的技术
3)『volatile变量』和可见性的关系
四、Volatile变量
第一节 可见性
②举例
1)什么是发布(Publish)一个对象
①有时需要『不发布对象』
②有时需要『发布对象』
③有时需要『发布对象,并确保对象的线程安全性』
2)不同的需求
3)为什么说,发布对象可能会破坏对象的『线程安全性』
4)什么是逸出(Escape)
5)发布对象的几个方法
①代码
②解释
③结论
6)发布对象——举例说明
A、叙述
B、包括
③什么是 Alien 外部方法
⑤为什么是『相当于』
B、代码
C、解释
⑥解决方案——如何才能不逸出
7)逸出——举例说明
8)发布内部类实例,会连带发布其外围类实例
二、安全的对象构造过程(思维导图,缓一缓)
第二节 发布与逸出
1、同步
②原因
③如何实现一个对象(数据的一种),只由单个线程独占
2、不共享:『线程封闭』
3、不可变
1)实现『线程安全』的几个办法
2)『同步』技术和『线程封闭』技术的比较
1、局部变量
2、ThreadLocal 类
3)Java 语言及其核心库中,维持『线程封闭性』的一些机制
1、例子叙述
2、如何在程序中,实现 Connection 对象的线程封闭
3、为什么JDBC规范,并不要求 Connection 对象必须是线程安全的
4)线程封闭技术举例
一、基本概念
1)Ad-hoc 线程封闭 (不是很懂,思维导图,暂时不做)
1、『栈封闭』与『线程封闭』的关系?
2、『栈封闭』的充分条件是什么
3、为什么说,『封闭在执行线程中』是『局部变量』的固有属性
4、『栈封闭』相较于『Adhoc线程封闭』的优点
解释
5、代码举例
②我的猜想
③举例
6、为什么说,对于『基本类型的局部变量』无论如何都不会破坏『栈封闭性』
①当前『集合animals』的引用,『封闭在执行线程』中
②发布引用,对象逸出
③引用、对象的存储位置
2)栈封闭
1、原理
2、作用
①单线程中的『数据库连接——Connection对象』
②多线程中的『数据库连接——Connection对象』
3、举例说明
4、线程封闭的Connection对象,举例说明
6、如何『单线程应用程序』移植到『多线程环境』
7、在实现应用程序框架时,大量使用了ThreadLocal
8、开发人员经常滥用ThreadLocal
3)ThreadLocal 类
二、三种分类
第三节 防止发布(线程封闭)
①此前介绍了许多,与原子性和可见性,相关的问题
②根本原因
1)带来『原子性』和『内存可见性』的根本原因
2)一种解决思路
3)什么是『不可变对象』
4)为什么说,线程安全性是『不可变对象』的固有属性之一
5)不可变对象一定是线程安全的
6)为什么说,不可变对象很简单
7)为什么『不可变对象』相较于『可变对象』更加可信
1、不可变对象内部,使用不可变对象来管理它们的状态(也即不可变对象嵌套,也即权威final)
2、不可变对象内部,使用可变对象来管理它们的状态,但是可变对象,不能对外发布
8)定义不可变对象的两种方法
9)所有的域都声明为final类型,就是不可变性对象吗?
①对象创建以后,其状态就不能修改
②对象的所有域,都是final类型
10)满足不可变对象的几个条件
②解释:不清楚——为什么是这样
②条件
1、final的作用?
2、什么时候使用『不可变对象』
①『除非需要更高的可见性,否则应该将所有的域都声明为私有域』
②『除非需要某个域是可变的,否则应该将其声明为final域』
4、良好的编程习惯
二、Final
三、使用『Volatile类型』来发布『不可变对象』(思维导图,下次做)
1、使用 final
2、不定义 setter方法
3、不定义 getter 或其它方法,返回状态的引用(如果状态是一个对象的情况下)
四、定义不可变对象的两个方法
第四节 不变性
1、什么时候你不能发布对象
2、如何确保对象不被发布
3、什么情况下,你需要发布对象
②疑惑
③原因
④解释
4、不安全的发布
一、
1、什么是『未被正确发布』
2、在『未被正确发布的对象』中存在哪两个问题
3、以上三种情况,没有理解是什么回事!!
二、不正确的发布:正确的对象被破坏
三、不可变对象与初始化安全性
四、安全发布的常用模式
第五节 安全发布
第三章 对象的共享
1、找出『构成对象状态』的『所有变量』
2、找出约束状态变量的『不变性条件』
3、建立『对象状态』的『并发访问』『管理策略』
1)设计线程安全类的三个基本要素
1、如果对象中所有的域都是『基本类型的变量』
2、如果在对象的域中引用了其他对象
2)如何分析『对象的状态』?
1、说法一
2、说法二
3)什么是同步策略(Synchronization Policy)
4)为什么必须将『同步策略』写为『正式文档』
一、概述
1)什么是收集同步需求
1、在『并发访问的情况下』,为什么要防止,线程的『不变性条件』,遭到破坏
2、如何防止,类的『不变性条件』,遭到破坏
3、什么是『状态空间』
4、『状态空间』大小与『可能状态』分析难度
5、『不可变条件』的作用?
A、例子
B、状态空间
C、不可变条件
D、关系
6、『不可变条件』与『状态空间』的举例说明:
2)不可变条件
①『后验条件』的作用?
②『后验条件』举例
③什么时候,不需要『后验条件』?
④举例说明——不需要『后验条件』的情况
3)后验条件
二、收集同步需求
1)换一种说法
2)如何满足不变性条件
3)如何满足后验条件
①封装——》满足『不变性条件』——》避免产生『无效状态』
②同步——满足『后验条件』——》避免产生『无效的状态转换』
③说明
4)方式比较
2、存在着什么特殊情况
3、举例
4、为什么『包含多个变量的不变性条件』将带来原子性需求
5)存在的问题
①『不变性条件』可能带来原子性要求
②『后验条件』可能带来原子性要求
A、差异叙述
B、共同合作
③举例说明:『后验条件』与『不变性条件』是不同的
6)为什么『不变性条件』和『后验条件』都会带来原子性要求
三、如何满足同步需求
①『先验条件』
②『后验条件』
1、作用叙述
2、举例
A、『先验条件』
B、『后验条件』
3、对比
1)『先验条件』
2)什么是『依赖状态的操作』
①在『单线程程序』中
②在『并发程序』中
3)『单线程和多线程』中的『先验条件』
1、使用在『平台与类库中』提供的『各种底层机制』来『创建依赖状态的类』(第14章将介绍)
2、一种更简单的方法——利用『现有类库』:(第5章将介绍)
3、阻塞类是同步工具类的子集,阻塞类包括——阻塞队列(Blocking Queue)或信号量(Semaphore)
4)如何实现『依赖状态的操作』?也即如何『实现』某个『等待先验条件为真时』才执行的『操作』
四、依赖状态的操作
a、不同点
b、相同点
A、什么是对象图——从对象图与类图的关系说起
1、对象的状态,包括哪些
四、状态的所有权
第一节 设计线程安全的类
第四章 对象的组合
并发实战
0 条评论
回复 删除
下一页