第2章 线程安全性
来源:互联网 发布:貂蝉离间数据 编辑:程序博客网 时间:2024/05/15 21:39
第2章 线程安全性
- 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问。
- 对象的状态,从非正式的意义上说,指存储在状态变量(例如实例或静态域)中的数据,对象的状态中包含了任何可能影响其外部可见行为的数据
- “共享”意味着变量可以由多个线程同时访问
- “可变”意味着变量的值在其生命周期内可以发生变化。
- 一个对象是否需要是线程安全的,取决于它是否被多个线程访问。这指的是在程序中访问对象的方式,而不是对象要实现的功能。
- 避免一个状态变量因并发访问产生错误,有三种办法:
- 不在线程间共享该变量
- 将该变量设为不可变的
- 使用同步访问该变量
2.1 什么是线程安全性
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
理解:在线程安全的类中封装了必要的同步机制,因此客户端无须进一步采取同步措施。
无状态对象一定是线程安全的。
2.2原子性
理解:通常指一个操作或一组操作是不可分割的
2.2.1竞态条件
所谓竞态条件,指某个计算的正确性取决于多个线程的交替执行时序时,就会发生竞态条件。
最常见的竞态条件类型就是“先检查-后执行”和“读取-修改-写入”操作,即通过一个可能失效的观察结果来决定下一步的动作。”先检查-后执行”的典型场景是延迟初始化,“读取-修改-写入”的典型场景是递增一个计数器。这些操作也称为复合操作,即包含了一组必须以原子方式执行的操作以确保线程安全性。
2.3加锁机制
要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。
2.3.1内置锁
java提供了一种内置的锁机制来支持原子性:同步代码块。同步代码块的锁就是方法调用所在的对象。静态的synchronized
方法以Class
对象作为锁。
每个java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁。获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。
2.3.2重入
内置锁是可重入的,这意味着如果一个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。这说明,java中获取锁的操作的粒度是“线程”而不是“调用”。重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。
2.4用锁来保护状态
对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一把锁,在这种情况下,我们称状态变量是由这个锁保护的。
对象的内置锁与其状态之间没有内在的关联。当获取一个对象内置的锁时,并不能阻止其他线程访问该对象,某个线程在获得对象的锁之后,只能阻止其他线程获得同一个锁。
每个共享的和可变的变量都应该只由一个锁来保护,从而使维护人员知道是哪一个锁。
一种常见的加锁约定是,将所有的可变状态都封装在对象内部,并通过对象的内置锁对所有访问可变状态的代码路径进行同步,使得在该对象上不会发生并发访问。
对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。
2.5活跃性与性能
通常,在简单性与性能之间存在着相互制约因素,当实现某个同步策略时,一定不要盲目地为了性能而牺牲简单性(这可能破坏安全性)。
当执行时间较长的计算或者可能无法快速完成的操作时(例如,网络I/O或控制台I/O),一定不要持有锁。
- 第2章 线程安全性
- 第2章 线程安全性
- 第2章-线程安全性
- 第2章-线程安全性
- 《第2章:线程安全性》一种常见的加锁约定
- 第二章 线程安全性
- 2 线程安全性
- 2线程安全性
- 2线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- 线程安全性
- GPS定位
- Learning FP-Growth Algorithm in Python
- 字符串及垃圾回收机制
- Correct use of System.Web.HttpResponse.Redirect
- Linux下安装并配置Weblogic运行环境
- 第2章 线程安全性
- [python] LDA处理文档主题分布代码入门笔记
- js用currentStyle和getComputedStyle获取css样式(非行间)
- 操作对象-小测试(完善) 获取运算后的值
- 构造函数中,哪些成员变量一定要通过初始化列表来初始化
- 下面哪些机制可以用于进程间通信?
- 数据挖掘学习路线
- 单例模式(Singleton)
- 原码、补码、运算(加减、异或)实例