竞争条件和临界区

549 阅读2分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

竞争条件和临界区

临界区指的是多个线程执行的代码块,由于执行顺序不同会导致结果不同的代码块。当多个线程执行临界区的代码导致结果差异时,则将其称为临界区包含竞争条件。

两个竞争条件

当多个线程以下面两种方式之一对变量进行操作时,便有可能触发竞争条件:

  • 读-修改-写
  • 检查-操作 具体来看一下这两种模式触发竞争条件的原因。
  • 读-修改-写模式意味这多个线程首先读取到变量,随后将变量修改后写入。新的数据则以某种算法依赖于读取到的值。如果两个线程同时读取到数据,同时进行修改数据,再同时将数据写回到内存中,则会产生数据与结果的不统一。
  • 检查-修改模式意味着多个给定检查条件,如果两个线程同时检查给定值,然后两个线程都尝试修改该值,便有可能发生这种问题。实际上只有一个线程获取的是原始值,另一个线程可能获取到修改后的值。

读-修改-写临界区

    public class Counter {
         protected long count = 0;
         public void add(long value){
             this.count = this.count + value;
         }
      }

当多个线程同时在执行counter实例的add方法时,无法知道cpu何时从两个线程间进行切换。add方法不会作为原子性进行执行,会分为读、增加、写三个部分。当cpu的切换在两个线程均进行读取后切换,与在其中一个线程执行后第二线程才进行读取,二者的结果存在差异。

检查-操作临界区

如果两个线程执行同一段代码,先对变量status进行检查,检查后如果status为0则进行相应逻辑操作并修改变量。可想而知,由于读取顺序的不同,会导致其中一个线程对逻辑代码的执行结果不同。

防止竞争条件

为了防止发生竞争条件,必须确保临界区作为原子指令执行。这意味着一旦一个线程正在执行它,在第一个线程离开临界区之前,其他线程都不能执行它。也就是说需要利用synchronized关键字或锁等方式保证原子性。

临界区吞吐量

对于较小的临界区,可以对整体代码进行锁定。而对于较大的临界区,需要将锁细化,对局部进行操作。

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。