第二章-线程安全性


什么是线程安全性?

定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,就称这个类是线程安全的。

无状态对象一定是线程安全的。大多数Servelt都是无状态的。


原子性

原子操作避免竞态条件

在没有同步的情况下统计已处理请求数量的Servlet
++count:并不是原子性的,读取-修改-写入
没有同步的情况下,会由于不恰当的执行时序出现不正确的结果:竞态条件

竞态条件

当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。

最常见的竞态条件类型

先检查后执行

解析:首先观察到某个条件(例如文件X不存在)为真,任何根据这个结果采用相应的动作(创建文件X),但事实上,在你观察到这个结果以及开始创建文件之前,观察结果可能变得无效(另一个线程在这期间创建了文件X),从而导致各种问题(未预期的异常、数据被覆盖、文件被破坏等)

竞态条件举例

递增命中计数器

延迟初始化

在这里插入图片描述
该程序包含了一个竞态条件:两个线程同时执行getInstance,如果时序未知,可能出现两个不同的实例。

原子变量类

AtomicLong

在java.util.concurrent.atomic包中,包含了一些原子变量类,用于实现在数值和对象引用上的原子状态转换。

在实际情况中,应尽可能使用现有的线程安全对象(例如AtomicLong)来管理类的状态
当在无状态的类中添加一个状态时(如count),如果该状态完全由线程安全的对象来管理,那么这个类仍然是线程安全的。

加锁机制

内置锁

  1. java提供了一种内置的锁机制来支持原子性:同步代码块
  2. 同步代码块包括2部分:一个作为锁的对象引用,一个作为由这个锁保护的代码块。
  3. 以关键字synchronized来修饰的方法就是同步代码块,其中该同步代码块的锁就是方法调用所在的对象。静态的synchronized方法以Class对象作为锁。
  4. 每个java对象都可以用作一个实现同步的锁,这些锁称为内置锁或监视器锁。线程在进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁。
    在这里插入图片描述

重入

内置锁是可以重入的,如果某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。
重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。当计数器为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将记下锁的持有者,并且将计数器置为1。如果同一个线程再次获取这个锁时,计数值将递增,而当线程退出同步代码块时,计数器会相应地递减。当计数值为0时,这个锁将被释放。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值