Java并发编程实践-教程-08章.pdf
文本预览下载声明
第八章 原子变量与非阻塞算法
第八章 原子变量与非阻塞算法1
8.1. 锁的劣势2
8.2. 原子变量类2
8.3. 非阻塞算法5
参考文献8
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
本章首先分析锁的劣势,然后分析原子变量类和非阻塞算法的优势。本章内
容与第3 章和第4 章内容,紧密相关。相关内容情况参考前述章节。
8.1. 锁的劣势
从前面的章节可以看到,使用一致的加锁协议来协调对共享状态的访问,确
保当线程持有守护变量的锁时,线程都能独占地访问这些变量,并且保证随后获
得同一锁的线程都能看见该线程对变量所作的修改。
Java 虚拟机能够对非竞争锁的获取和释放进行优化,让它们非常高效,但是
如果有多个线程同时请求锁,Java 虚拟机就需要向操作系统寻求帮助。倘若了出
现这种情况,一些线程将可能被挂起,并稍后恢复运行。从线程开始恢复,到它
真正被调度前,可能必须等待其他线程完成它们的调度限额规定的时问。挂起和
恢复线程会带来很大的开销,并通常伴有冗长的中断。对于基于锁,并且其操作
过度细分的类(比如同步容器类,大多数方法只包含很少的操作),当频繁地发
生锁的竞争时,调度与真正用于工作的开销间的比值会很可观。
加锁还有其他的缺点。当一个线程正在等待锁时,它不能做任何其他事情。
如果一个线程在持有锁的情况下发生了延迟(原因包括页错误、调度延迟,或者
类似情况),那么其他所有需要该锁的线程都不能前进了。如果阻塞的线程是优
先级很高的线程,持有锁的线程优先级较低,那么会造成性能风险,被称为优先
级倒置(priority inversion )。即虽然更高的优先级占先,但它仍然需要等待锁被
释放,这导致它的优先级会降至与优先级较低的线程相同的水平。如果持有锁的
线程发生了永久性的阻塞(因为无限循环、死锁、活锁和其他活跃度失败),所
有等待该锁的线程都不会前进了。
即使忽略上述的风险,加锁对于小的操作而言,仍然是重量级(heavy weight )
的机制,比如自增操作。需要有更好的技术用来管理线程之问的竞争。在Java 5.0
中,使用原子变量类(atomic variable classes )能够高效地构建非阻塞算法。
8.2. 原子变量类
在JDK 5.0 之前,如果不使用本机代码,就不能用Java 语言编写无等待、
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
无锁定的算法。在java.util.concurrent 中添加原子变量类之后,这种情况发生了
变化。本节了解这些新类开发高度可伸缩的无阻塞算法。
java.util.concurrent.atomic 包中添加原子变量类。所有原子变量类都公开“比
较并设置”原语(与比较并交换类似),这些原语都是使用平台上可用的最快本
机结构(比较并交换、加载链接/条件存储,最坏的情况下是旋转锁)来实现的。
原子变量类共有12 个,分成4 组:计量器、域更新器(field updater )、数组
以及复合变量。最常用的原子变量是计量器:AtomicInteger 、AtomicLong 、
AtomicBoolean 以及AtomicReference 。他们都支持CAS (比较并设置,详细参考
第3 章);AtomicInteger 和AtomicLong 还支持算术运算。
原子变量类可以认为是volatile 变量的泛化,它扩展了volati
显示全部