哈尔滨工业大学软件构造课程笔记第七章第二节

7.2 线程安全

1.什么是线程安全

线程安全
竞争条件:多个线程共享同一个可变变量,但不协调它们正在做的事情。

这是不安全的,因为程序的正确性可能依赖于低级操作的定时事故。

线程之间的“竞争条件”:作用于同一个mutable数据上的多个线程,彼此之间存在对该数据的访问竞争并导致interleaving,导致postcondition可能被违反,这是不安全的。

threadsafe是什么意思
线程安全:ADT或方法在多线程中要执行正确

如何抓住这个想法?
不违反spec、保持RI
与多少处理器、OS如何调度线程,均无关
不需要在spec中强制要求client满足某种“线程安全”的义务

Iterator是不线程安全的,Iterator的规范规定,不能在对集合进行迭代的同时修改集合。这是设置在调用者上的与时间相关的前置条件如果你违反了它,Iterator不能保证你的行为是正确的

threadsafe是什么意思:remove()的spec
作为这种非本地合同现象的一个症状,考虑到Java集合类,通常在客户端和类的实现者之间用非常清晰的契约来记录。
-试着找到它在哪里记录了客户端的关键需求,即当你迭代一个集合时你不能修改它。
在这里插入图片描述
threadsafe的四种方式
限制数据共享
共享不可变数据
共享线程安全的可变数据
同步机制:通过锁的机制共享线程不安全的可变数据,变并行为串行

策略1:Confinement限制数据共享

限制数据共享
将可变数据限制在单一线程内部,避免竞争
不允许任何线程直接读写该数据
核心思想:线程之间不共享mutable数据类型
局部变量总是线程限制。一个局部变量存储在堆栈中,并且每个线程都有自己的堆栈。一个方法可能有多个调用同时运行,但是每个调用都有自己的变量私有副本,因此变量本身是受限的。
如果一个局部变量是一个对象引用,你需要检查它指向的对象。如果对象是可变的,那么我们需要检查对象是否也被限制了——不能有任何其他线程可访问(非别名)的对它的引用

内部Java内存模型
JVM内部使用的Java内存模型在线程堆栈和堆之间划分内存。
在这里插入图片描述在这里插入图片描述
内部Java内存模型:堆栈
每个线程有自己的栈
栈中包含所有方法的局部变量
线程只能访问自己的线程栈
线程创建的局部变量其他线程不可见
即使两个线程的代码一样,创建的同名变量仍然在各自的栈中
每个线程有自己版本的局部变量

内部Java内存模型:堆
基本类型的局部变量保存在线程栈中
一个线程可能会将基本类型变量的副本传递给另一个线程,但它本身不能共享基本类型局部变量
对象类型数据保存在堆中
如果对象被指派到某个局部变量,或者作为其他对象的成员变量,创建的对象仍然在堆中

Java内存模式的几个关键点
基本数据类型的局部变量保存在线程栈中
局部变量引用了对象,引用保存在栈中,对象本身存储在堆中
对象包含的方法和方法包含的局部变量存储在栈中
对象的成员变量同对象一起存储在堆中,不论成员变量的类型是基本类型还是对象类型(对其他对象的引用)
静态的类变量同类的定义一起保存在堆中
堆中的对象可以被所有拥有引用的线程访问
如果两个线程同时调用同一个对象上的一个方法,它们都可以访问该对象的成员变量,但是每个线程都有自己的局部变量副本。
在这里插入图片描述
避免全局变量
全局静态变量不会自动被线程限制。
如果你的程序中有静态变量,那么你必须证明只有一个线程会使用它们,并且你必须清楚地记录这个事实。
更好的是,应该完全消除静态变量

限制数据共享和filed
即使实例变量被声明为私有,它们也

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值