什么是Race Condition?

简介

race condition是多线程的应用程序中经常遇到的问题,本文章接下来会解释什么是race condition,如何检测到它们以及如何解决这类问题。

Race condition

从定义来说,race condition是代码中一些执行结果取决于其执行的相对时间或者多线程交错执行的判断条件。它的结果是不可预测的。如何一个程序中不存在race condition,那么它就是线程安全的(thread-safe)。

例如有个转账程序,假设有两个账户,里面的余额都是500,现在要分两次从A账户转账300到B账户,如下图:
在这里插入图片描述

这两次转账操作分别有一个线程执行。如果第二次转账是在第一次转账后发生的,那么第二次转账就会判断发现A账户余额不足,从而转账失败。
在这里插入图片描述
但是,如果这两次转账在两个线程内同时执行,那么就可能出现不可预测的结果。如下图,两个线程检查A账户月都是500,都进行了转账操作,结果A账户最后余额是-100,这样的结果明显是不正确的。
在这里插入图片描述
如上转账过程,由于线程的执行时机是任意的,所以执行的结果也是不可预测的。造成这一情况的正是race condition(上面判断账户是否大于300的判断)。为了避免race condition,所以的共享资源(在例子中两个账户的余额可以被多个线程读取操作,所以余额就是共享资源)必须原子性地操作。打到这个目标有两个方法,第一种是将多个操作封装成一个线程排他性的代码段(例如加锁),第二是从硬件上保证是这些操作的原子性。

Race condition的两个模式

Check-Then-Act

Race condition有两个模式,第一个就是上面的转账的例子,属于Check-Then-Act模式,这类模式通常是一个流程中有一个检查环节,通过检查的结果再决定后续怎么走。

懒加载是Check-Then-Act的第二例子,例如在单例模式中,懒汉模式如下:

class Singleton {
    public static Object singleton;

    public static Object getSingleton(){
        if (singleton == null) {
            singleton = new Object();
        }
        return singleton;
    }
}

上面的singleton == null就是一个race condition,根据上面的解决办法,最简单是加上synchronized关键字,让判断和赋值两个操作具有线程排他性。

Read-Modify-Write

Read-Modify-Write是race condtion的第二个模式。在大多数编程语言中,对一个变量的修改通常分为读取,修改,写入三个步骤。问题通常是对变量的并发的读取修改(至少有一个修改,纯读取是没问题的)引起的。例如:
在这里插入图片描述
由于count++不是原子操作,所以可能发生以下情形:
在这里插入图片描述
两个线程同时对count进行++操作,结果并没有加2。

如何检测race condition

race condition通常很难重现,定位和排除,因为问题发生依赖于特定的场景。即使写一个多线程的单元也不可以保证程序的100%的正确定,但有一些方法可以排除race condition。

如何避免race condition

1.避免使用共享变量

在多线程环境中,race condtion的出现往往伴随着共享变量,如上面例子中的账户余额和count变量,都可以被多个线程读取操作,那么避免问题发生最简单直接的办法就是避免使用共享变量。可以使用不可变对象或者线程本地对象(例如java中的threadlocal)。

2.使用同步或者原子操作

使用同步可以避免race condition的问题,但是线程同步往往伴随很多同步的性能开销,还可能导致死锁。两个办法是使用原子操作,例如java中的提供的原子类。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值