用不变对象解决竞态问题
不可变对象
所有并发问题都是由于多个线程同时访问对象的某个可变属性引起的, 如果对象是不可变的, 那么所有的并发问题都将迎刃而解.
所谓不可变对象是指对象一旦构造完成, 其所有属性就不能更改, 不可变对象显然都是线程安全的.
对于不可变对象, 需要防止发生this逃逸.
如果需要对多个成员进行一项原子操作, 可以考虑使用这些成员构建一个不可变类. 例如:
Java代码
文章图片
【用不变对象解决竞态问题】publicclassCashedClass {
privateString cashedStr ="";
privateintcashedHashCode;
publicinthashCode(String str) {
// 如果str是cashedStr, 就直接返回缓存的hashCode值
if(str.equals(cashedStr)) {
returncashedHashCode;
}else{
// 将cashedStr和hashCode值缓存起来
cashedStr = str;
cashedHashCode = cashedStr.hashCode();
returncashedHashCode;
}
}
}
CashedClass不是一个线程安全的类, 因为对cashedStr和cashedHashCode的读写操作不具备原子性, 会发生race condition. 除了使用synchronized进行同步之外, 我们还可以使用不可变对象消除race condition:
Java代码
文章图片
publicclassCashedClass {
// 使用一个volatile变量持有OneCashedValue对象
privatevolatileOneCashedValue oneValue =https://www.it610.com/article/newOneCashedValue("",0);
publicinthashCode(String str) {
inthashCode = oneValue.getStrHashCode(str);
if(hashCode == -1) {
hashCode = str.hashCode();
// 对volatile变量的修改不依赖于当前值, 符合volatile的使用场景
oneValue =https://www.it610.com/article/newOneCashedValue(str, hashCode);
}
returnhashCode;
}
/**
* 这是一个不可变类
*/
publicclassOneCashedValue {
// 成员变量都是final的
privatefinalString str;
privatefinalintstrHashCode;
// 构造过程中不会发生this逃逸
publicOneCashedValue(String str,intstrHashCode) {
this.str = str;
this.strHashCode = strHashCode;
}
publicintgetStrHashCode(String str) {
if(!this.str.equals(str)) {
// -1表示无效的hashCode值
return-1;
}
returnstrHashCode;
}
}
}
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 涉毒患者(新诗)
- 参保人员因患病来不及到指定的医疗机构就医,能否报销医疗费用()
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。