线程安全性的基本概念

线程安全性

      我们总是说要编写线程安全的代码,有时候也会讨论某个类是不是线程安全的。那到底什么是线程安全性呢?
      网上有很多说法:可以被多个线程调用,并且线程之间不会出现错误的交互;
多个线程调用时,不需要做额外的动作等等。
但这话,明明什么都说了,又好像什么都没有说。到底怎么才能在多个线程之间安全地调用呢,怎么算安全呢?

正确性

      在线程安全性定义中,最核心的概念就是正确性。如果对线程安全性的一定是模糊的,那么就是缺乏对正确性的清晰定义。
    正确性的含义是:这个类的行为与其规范完全一致。我们通常不会为一个类编写详细的规范,但是这并不妨碍我们对正确性的理解,在写一个类、一个方法的时候,对于这个类的作用,这个方法的执行我们是有一个预期结果的。如果在多线程环境下,多个线程都在调用的时候,这个类这个方法仍然能始终保持预期的行为与结果,就是符合正确性的。在对正确性有一个比较清楚的认知之后,就可以定义线程安全性了:

当多个线程访问某个类时,不管这些线程如何交替执行,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的

对共享和可变的状态访问操作进行管理

      那么如何做才能让类在多线程的环境下始终表现正确呢,换句话说,多线程环境下如何避免类出现不可预知,预料之外的行为。核心在于:要对状态访问操作进行管理,特别是对共享的和可变的状态的访问。
      对象的状态指的是存储在状态变量(例如实例或者静态域、成员变量)中的数据。对象的状态可能包含依赖的其它对象的状态。例如HashMap的状态不仅仅存储在HashMap本身,还存储许多Map.Entry对象中。在对象的状态中包含了任何可能影响其外部可见行为的数据。
      共享意味着可以由多个线程同时访问、可变则意味这变量的值在整个生命周期中可以发生改变。当多个线程访问某个状态变量,并且至少有一个线程会修改变量的值时,就需要采用同步机制来协调这些线程对对象的访问。这里说的”同步机制“包括:synchronized关键字、volatile变量、显式锁、ThreadLoacl变量以及原子变量。

当多个线程同时访问一个可变的状态变量时,如果没有采用合适的同步,程序会出现错误。有3中方式可以解决这个问题。
      1.不在线程之间共享该状态变量
      2. 将状态变量修改为不可变变量
      3.在变量访问时采用合适的同步

原子性、可见性、有序性

      经常看到一种说法,叫”多线程的三个特性:原子性、可见性、有序性“。什么意思?多线程跟这三个东西有什么关系?
      按照我的理解,原子性、可见性和有序性是代码执行的特征,为什么许多单线程下正常运行的代码跑的好好的,一旦多个线程同时访问就会出现莫名其妙的问题!恰恰是因为多线程破坏了这3个规则,在单线程环境下i++操作是原子的,但是到了多线程访问时,它就不是原子性了。多线程编程时我们为什么要加锁,要给变量加volatile关键词,要采取各种同步机制,就是需要保证不破坏原子性、可见性,保证有序性。

原子性:

一个操作或者多个操作,要么全部执行并且执行过程中不会被任何因素打断,要么不执行。

  1. 竞态条件
    当某个计算的正确性,取决与多个线程交替执行的时序时,就会发生竞态条件。典型的竞态条件就是:先检查后更新,本质上是:基于一种可能失效的观察结果来做出判断或者执行操作
    例如我们常见的 i++操作,其实包含了3个操作。先获取i的值,将i的值加1,将加1后的值写入变量i。
    如果没有进行合适的同步(将上面3个操作整合为原子操作),多个线程同时执行会得到不符合预期的结果:可能两个线程都得到2。
    2.复合操作
    有时候我们需要一组操作以原子方式执行,在执行过程中要防止其它线程使用这个变量。只能允许其它线程在复合操作执行前或者执行后访问状态变量,而不是在修改的过程中。

可见性

多个线程同时访问一个共享变量时,某个线程修改了共享变量,其它线程能够立即获取到修改后的值

有序性

程序的执行顺序按照代码的先后顺序执行
由于指令重排等虚拟机优化策略,可能会导致程序的执行顺序并不严格按照代码的顺序。
多线程就是需要保证这3个特性的正常执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值