java后验条件_JAVA并发实战学习笔记——3,4章~
JAVA并发实战学习笔记
第三章 对象的共享
失效数据:
- java程序实际运行中会出现①程序执行顺序对打乱;②数据对其它线程不可见——两种情况
- 上述两种情况导致在缺乏同步的程序中出现失效数据这一现象,且“失效”这一情况不确定性很大,因为可能出现可能没出现。
JVM中没有规定对于64位变量如:long, double 的读写操作必须是原子的,因此不同步的情况下读取该类数据可能得到的值无意义(低32位和高32位没有一起形成完整的数字)
- 商用的JVM一般会让64位变量的读取原子化。
使用volatile修饰变量可以保证变量的可见性,但不会保证互斥性,是比内置锁更弱的同步机制。
在以下两种情况下可以使用volatle保证同步。但是过度依赖volatile会使得代码脆弱、可读性差。
- 1.只有一个线程对volatile变量实行写操作;
- 2.变量不需要与其它状态变量共同参与不变约束。
- 加锁操作兼保证原子性和可见性
发布(将变量的引用保存到其它代码可以访问到的地方)与逸出(不该发布的变量被发布了):
发布的几种方式:
- public static A
- 某个对象A的引用在另一个对象B中,发布B则间接地发布了A
- 将对象传递给外部方法
- 发布内部类对象A,A中隐含地包含了外部类对象B
逸出
- 在构造函数中启动了新线程(该对象的内部线程类),使得this指针在实例没有建好时便被其它线程共享了。
线程封闭:线程封闭是一类编程的方法,使得各个线程中的对象是不相互共享的,如:JDBC中的Connection对象
- Ad-hoc线程封闭:尽量少用,十分脆弱
栈封闭:局部变量由于在运行中是处于线程栈的局部变量表和操作数栈中,所以局部变量无论是否是线程安全,只要其引用不发布出去,都是线程安全的。
- 以能用局部变量就别用全局的变量,全局变量容易引起并发问题。
ThreadLocal类线程封闭:可将ThreadLocal t 看成是Map<Thread,T> t,保存了每个线程到T对象的一份副本,t.get()得到的是initialValue()设定的值。
- 副本保存在线程中,随着线程的技术被垃圾回收
- 引入了类之间的耦合性,小心使用
- ThreadLocal类应用场景示例:移植单线程程序到多线程环境
不变性
满足下列三个条件的对象满足“对象不可变”
- 创建好后,不提供更改其状态的方法
- 所有的域都是 final型
- 对象是正确创建的
- “对象引用不可变”————相比于对象不可变,对象的内容可以改变,但是对象地址无法改变(即用final修饰的变量)
不可变对象为一系列操作提供弱原子性
- 只要将参数传入方法,在该方法内就有指向域的引用,其它的线程修改了原对象的域,也不会影响到该方法对原域的访问。
安全发布————确保可以不受JAVA不可见性的影响,得到发布的最新的对象
不可变对象安全发布的方式
- final域具有特殊的初始化安全性保证,在初始化的时候即使没有同步,也可以保证其可见性。
可变对象安全发布的方式
- 静态初始化对象(标有static的对象初始化代码是在类初始化阶段执行的,JVM自带线程安全特性)
- 将对象的引用保存在volatile类型的域中,或者AtomicReference对象中
- 对象引用存入final类型域中
- 将对象引用存入某个由锁保护的域中
安全访问
事实不可变对象和不可变对象
- 任意访问
可变对象
- 访问时需要同步机制,对象需要是线程安全,或者访问前先获得某个锁
第四章 对象的组合
如何建立线程安全的类
1.收集同步需求————候选范围为对象的域,包括对象中包含的基本类型变量,以及域对象,和域对象内的域
不变性条件
- 单个变量,即变量的值需要在其合法范围内
- 多个变量,即多个变量的值之间需要满足某些约束
- 访问同一个不变性条件中任何一个变量,都需要获得同一个锁,以确保对操作不会破坏不变性条件
后验条件
- 变量的值转换需要满足的约束
- 不变性条件和后验条件约束了对象的哪些状态和状态转换是有效的
- 2.先验条件————即依赖状态的操作
实例封闭————使封装的数据被封闭在另一个对象中,被封闭的对象不超出其作用域????
一般知识
- 将对实例内封装的对象的访问限制在对象的方法上,以确保线程在访问数据是总能持有正确的锁.
含有线程不安全的内部对象的线程安全类示例:
- Collections.synchronized***()方法通过装饰器模式将容器封装在一个线程安全的对象中
public class PersonSet{
private final Set myset = new HashSet;
public synchronized void addPerson(Person p){
myset.add(p);
}
public synchronized boolean containsPerson(Person p){
return myset.contains(p);
}
}
疑惑之处:
不超出作用域?如何保证方法有合适的返回值呢?觉得很奇怪。
安全发布状态变量的三个条件
- 1. 状态变量是线程安全的
- 2. 变量不存在不变性约束
- 3. 在方法中不包含使得该变量进入不合法状态的操作
而且使用锁同步,和不使对象溢出有什么联系呢?我觉得这就是两个独立的东西,放在一起凑成一节,让人困惑
- 猜测:要实现非线程封闭的线程安全类,封闭对象是第一步,限制访问方法并使访问方法同步是第二步。
Java监视器模式(即私有的所对象,而非内置锁)
- 好处是不会让外部的方法得到该对象的锁
- 若容器内的对象是非线程安全的,可以每次发布该对象的时候都深度复制
线程安全性的委托
- 将线程安全性委托给单个/多个(彼此独立的对象,且所有的方法中都不包含无效状态转换操作)线程安全的状态
- 若类中包含不符合上一条要求的,包含多个有不
- 条件约束的状态,实现线程安全性需要加锁机制
在现有的线程安全类中添加新功能
- 在并发中,能用现成的线程安全类就尽量用;若现成的类满足不了需求,则可能选择添加新功能
四种方法:
- 改源码 ————不现实
扩展基础类 ———— 在自己的子类新添加的方法中使用内置锁——从这里来看,子类和父类中使用的内置锁应该是同一个,都是真对实例而言的。
- 缺点:破坏了类的封装性
客户端加锁机制 ———— 了解基础类对象使用的是什么锁,在客户端代码中使用相同的锁
- 缺点:破坏了同步策略的封装性
组合模式 ————使用装饰器模式将基础类如:list等封装在内部,将list的方法包装一层,使用装饰器类的内置锁。
优点
- 不会破坏封装性
- 健壮性更强
- 即使容器类不是线程安全的,也可以借此实现线程安全
缺点
- 多加一层锁,效率下降
文档!!!文档!!!
- 设计文档 & 用户文档
Java文档中应该注明该类使用的同步机制,应该包含下面一些内容
- 是否是线程安全的?
- 客户回调需不需要加锁,可以加那些锁?
- 哪些锁保护了哪些状态?(设计文档,可以用java注释便于后续开发)
原文:https://www.cnblogs.com/tanyalew/p/9340830.html
java后验条件_JAVA并发实战学习笔记——3,4章~相关推荐
- 网易云课堂微专业--Java高级开发工程师--多线程并发编程--学习笔记(二)
文章目录 第一章 多线程并发编程 第二节 线程安全问题 1.2.1 线程安全之可见性问题 多线程中的问题 从内存结构到内存模型 工作内存缓存 指令重排序 内存模型的含义 Shared Variable ...
- java中解决脏读_java并发编程学习之脏读代码示例及处理
使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即 ...
- java中线程总结_java中多线程学习笔记总结
线程的简单学习笔记: 1.进程与线程的概念 进程:从用户角度看进程是应用程序的一个执行过程. 从操作系统核心角度看进程代表的是操作系统分配的内存和CPU时间片等资源的基本单位,是为正在运行的程序提供的 ...
- Java秒杀系统方案优化 高性能高并发实战 学习笔记
秒杀系统 (一)搭建环境 自定义封装Result类 自定义封装CodeMsg类 集成redis和rabbit 封装RedisService类 断言和日志测试 (二)实现用户登录和分布式Session ...
- java 对象 线程安全_JAVA并发编程学习:构造线程安全的对象
设计线程安全的类 实例限制 当一个对象被另一个对象封装时,所有访问被被封装对象的代码路径就是全部可知的,这相比于让对象可被整个系统访问来说,更容易对代码路径进行分析.将数据封装在对象内部,把对数据的访 ...
- java公社博客_Java面向对象开发学习笔记(二)
课时4 类与对象(对象内存分析) 如果要想进行对象的产生分析,首先就必须清楚引用类型.引用类型指的是内存空间的操作.而对于现在的内存,我们主要使用两块内存空间: 堆内存空间:保存真正的数据,堆内存保存 ...
- java公社博客_Java面向对象开发学习笔记(一)
Java面向对象开发 共105课时 课时1 面向对象简介 面向对象是一种程序设计方法,但是并不是所有开发者都认同面向对象,因为很多开发者认为面向对象过于复杂,所以更多人愿意使用函数式编程. 面向对象的 ...
- Java 8 实战学习笔记
Java 8 实战学习笔记 @(JAVASE)[java8, 实战, lambda] 文章目录 Java 8 实战学习笔记 参考内容 Lambda表达式 Lambda环绕执行模式(抽离步骤) 原始代码 ...
- 先验条件、后验条件、不变条件
You'll have a lot of problems writing Java, especially multi-threaded code, if you can't understand ...
最新文章
- 相似图片检测:感知哈希算法之aHash,dHash,pHash的Python实现
- 【Java】5.5 深入构造器
- oracle触发器的类型及使用方法
- php ci nginx 伪静态rewrite配置方法
- 关于.cpp文件包含另一个.cpp文件出错的原因以及解决办法
- Flask常见问题记录
- 使用Lingo做灵敏度分析
- GB2312、GBK、UTF-8 如何转换
- xshell如何设置选中复制_Xshell
- 贪吃蛇php代码下载,C语言贪吃蛇代码
- 主编编辑器怎么把文章转成长图?
- ssl checker
- Unity3D关于iTween知识详解和接口总结
- Python面向对象加强4.iter与next的用法,枚举器enumerate
- 阅读笔记:利用Python进行数据分析第2版——第10章 数据聚合与分组运算
- 大学计算机实验报告u盘启动安装,用U盘安装Win7操作系统实验报告
- 网络字节序与主机字节序的转换 - HEN_MAN的专栏 - 博客频道 - CSDN.NET
- Mac 开启 HIDPI 设置各种分辨率 HIDPI mac high sierra 2k
- 微信会员卡,信息类目字段跳转小程序【custom_field1】【巨巨巨巨坑】
- Dev GridView网格中格式化 TimeSpan
热门文章
- ARM 学习知识点梳理
- 写技术博客,如何选择博客平台
- 祝贺深圳华南销售部成功签订广州某会议室室内P2.5全彩LED显示屏项目
- 摄像头基础介绍【转】
- 护士成绩用计算机改卷,解密!2020年卫生资格/护士人机对话考试如何评分?成绩如何核算?...
- 麻将服务端架设linux,湖南房卡麻将客户端/服务器端完整源码及编译教程
- 机器学习之推荐系统的基础知识
- 人一辈子必看的超级经典人生语录
- 生命在于学习——docker逃逸
- Python零基础速成班-第2讲-Python基础(上),运算、变量、数据类型、输入输出