Java并发编程实战 之 线程安全性
1.什么是线程安全性
当多个线程访问某个类时,不管运行时环境采用何种调用方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
无状态的对象一定是线程安全的,比如:Servlet。
2.原子性
2.1 竞争条件
由于不恰当的执行时序而出现不正确的结果的情况,就是竞争条件。
“先检查后执行”操作,即通过一个可能实效的观测结果来决定下一步的动作。比如:延迟初始化。
if(instance == null) {
instance = new SomeObject();
}
“读取-修改-写入”的操作,其结果状态依赖于之前的状态。如:递增运算。
long count = 0;
count++;
2.2 复合操作
原子操作是指,对于访问同一个状态的所有操作(包括此操作本身)来说,这个操作是以一个原子方式执行(不可分割)的操作。
为了确保线程安全性,包含了一组必须以原子方式执行的操作,称为复合操作。
递增运算可以使用一个现有的线程安全类,确保线程安全性。如:
AtomicLong count = new AtomicLong(0);
count.incrementAndGet();
3.加锁机制
当类只有一个状态变量时,可以通过线程安全的状态变量来维护类的线程安全性。但如果类有更多的状态时,就不能只添加更多线程安全的状态变量了。要保持状态的一致性,就需要在单个原子操作中更新所以相关的状态变量。
3.1 内置锁
Java提供一种内置锁:同步代码块,它包括:一个作为锁的对象引用、一个作为由这个锁保护的代码块。
以关键字synchronized来修饰的方法就是一种横跨整个方法体的同步代码块,其中该同步代码块的锁就是方法调用所在的对象。静态的synchronized方法以Class对象作为锁。
线程在进入同步代码块之前会自动获得锁,在退出同步代码块是自动释放锁。最多只有一个线程能持有这种锁,因此同步代码会以原子方式执行。
3.2 重入
内置锁是可重入的,意味着获取锁的操作的粒度是线程,不是调用。当某个线程试图获得一个已经由它自己持有的锁时,这个请求也会成功。
重入进一步提升了加锁行为的封装性,简化了面向对象并发代码的开发。
public class Widget {
public synchronized void doSomething() {
//......
}
}
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
//......
super.doSomething();//假如没有可重入的锁,该语句将产生死锁。
}
}
4.用锁保护状态
对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁,在这种情况下,称状态变量是由这个锁保护的。
5.活跃性与性能
粗粒度地使用锁,虽然确保了线程安全性,但可能造成性能问题和活跃度问题,如:
@ThreadSafe
public class SynchronizedFactorizer implements Servlet {
@GuardedBy("this") private BigInteger lastNumber;
@GuardedBy("this") private BigInteger[] lastFactors; public synchronized void service(ServletRequest req,
ServletResponse resp) {
BigInteger i = extractFromRequest(req);
if (i.equals(lastNumber))
encodeIntoResponse(resp, lastFactors);
else {
BigInteger[] factors = factor(i);//因数分解计算
lastNumber = i;
lastFactors = factors;//存放上一次计算结果
encodeIntoResponse(resp, factors);
}
}
}
可以通过缩小同步代码块,既确保servlet的并发型,又维护线程安全性。不要把本应是原子操作拆分到多个同步代码块中,尽量将不影响共享状态且执行时间较长的操作从同步代码中分离出来。如:
public class CachedFactorizer implements Servlet {
@GuardedBy("this") private BigInteger lastNumber;
@GuardedBy("this") private BigInteger[] lastFactors; public void service(ServletRequest req, ServletResponse resp){
BigInteger i = extractFromRequest(req);
BigInteger[] factors = null;
synchronized (this) {
if (i.equals(lastNumber)) {
factors = lastFactors.clone();
}
}
if (factors == null) {
factors = factor(i);
synchronized (this) {
lastNumber = i;
lastFactors = factors.clone();
}
}
encodeIntoResponse(resp, factors);
}
}
Java并发编程实战 之 线程安全性的更多相关文章
- java并发编程实战之线程安全性(一)
1.1什么是线程安全性 要对线程安全性给出一个确切的定义是非常复杂的.最核心的概念就是正确性.正确性:某个类的行为与其规范完全一致.在良好的规范中通常会定义各种不变性条件来约束对象的状态,以及定义各种 ...
- 【java并发编程实战】-----线程基本概念
学习Java并发已经有一个多月了,感觉有些东西学习一会儿了就会忘记,做了一些笔记但是不系统,对于Java并发这么大的"系统",需要自己好好总结.整理才能征服它.希望同仁们一起来学习 ...
- Java并发编程实战 05等待-通知机制和活跃性问题
Java并发编程系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 Java并发编程实 ...
- java并发编程实战学习(3)--基础构建模块
转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put ...
- 《Java并发编程实战》/童云兰译【PDF】下载
<Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...
- 《java并发编程实战》笔记
<java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为: Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...
- 《Java并发编程实战》文摘
更新时间:2017-06-03 <Java并发编程实战>文摘,有兴趣的朋友可以买本纸质书仔细研究下. 一 线程安全性 1.1 什么是线程安全性 当多个线程访问某个类时,不管运行时环境采用何 ...
- Java并发编程实战 04死锁了怎么办?
Java并发编程文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 前提 在第三篇 ...
- Java并发编程实战——读后感
未完待续. 阅读帮助 本文运用<如何阅读一本书>的学习方法进行学习. P15 表示对于书的第15页. Java并发编程实战简称为并发书或者该书之类的. 熟能生巧,不断地去理解,就像欣赏一部 ...
随机推荐
- [BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化)
Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天, ...
- Activiti就是这么简单
Activiti介绍 什么是Activiti? Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理.工作流.服务协作等领域的一个开 ...
- 发个2012年用java写的一个控制台小游戏
时间是把杀狗刀 突然发现了12年用java写的控制台玩的一个文字游戏,有兴趣的可以下载试试哈汪~ 里面难点当时确实遇到过,在计算倒计时的时候用了多线程,当时还写了好久才搞定.很怀念那个时间虽然不会做游 ...
- 关于字符latin capital letter sharp s "ß"( U+1E9E)显示的问题
今天测试产品时,遇到德语字符ß在网页上显示为”SS",查了一些相关资料发现这个字符一般用“ss"或"SS"取代. 需要注意,此字符与它的小写形式不同,小写字符l ...
- 网站压力测试ab 命令
网站压力测试ab 命令 author: headsen chen 2017-10-25 10:06:35 个人原创,转载请注明作者,出处,否则依法追究法律责任! 1,制作一个a ...
- python学习03-数据类型
一.基本数据类型--数字 布尔型 bool型只有两个值:True和False 之所以将bool值归类为数字,是因为我们也习惯用1表示True,0表示False. 以下是布尔值是False的各种情况: ...
- TypeScript入门(一)
TypeScript是微软官方的一种语言,是JavaScript的超集.它遵循的ECMA Script 6.0是下一代的JavaScript.浏览器还没有完全支持ES6,而ES5是弱类型的语言,还没有 ...
- MySQL聚集索引和非聚集索引
索引分为聚集索引和非聚集索引,mysql中不同的存储引擎对索引的底层实现可能会不同,这里只关注mysql的默认存储引擎InnoDB. 利用下面的命令可以查看默认的存储引擎 show variables ...
- 深入解析C语言数组和指针
概述 指针是C语言的重点,同时也是让初学者认为最难理解的部分.有人说它是C语言的灵魂,只有深入理解指针才能说理解了C语言.暂且撇开这些观点不谈.这章是我在阅读<C和指针>这本书的读书笔记. ...
- [jdoj1817]Drainage Ditches_网络流
Drainage Ditches jdoj-1817 题目大意:网络流裸求最大流 注释:n(点数),m(边数)<=200. 想法:裸的网络流求最大流,用bfs+dfs,美其名曰dinic. 没有 ...