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