什么是竞态条件
官方的定义是如果程序运行顺序的改变会影响最终结果,这就是一个竞态条件(race condition).
理解竞态条件首先要知道程序运行不一定是线性的。初学编程的时候都是从“面向过程编程“开始的,一条一条指令打下来,期待着他们会顺序执行。debug的使用也加深了这一认识。不过事实上如果两条紧挨着的指令没有依赖关系,jvm是有可能将他们的运行顺序倒转的。当然这是题外话,最显著的“不按顺序执行“的例子还是多线程程序。
Runnable r1 = () -> { // do something };
Runnable r2 = () -> { // do another thing };
new Thread(r1).start();
new Thread(r2).start();
上述程序定义了两个Runnable实例,并用它们新建两个线程,虽然r1先于r2开始,但他们内部的代码谁先谁后就不由而知了。
如果一段程序运行多次的结果不一致(排除生成随机数的情况),那这就可能是竞态条件的体现。比如最典型的例子,两个线程同时把一个类的静态成员做50词自增加1的操作,即
SomeClass.someMember++;
写在两个线程中,都运行50次,运行结束以后用主线程去取这个变量的值几乎不可能是100. 有的时候是97,有的时候是98,这是用来说明竞态条件的最有效例子。
竞态条件 & 临界区
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竞态条件发生的代码区称作临界区。