【问题标题】:Finding the race condition寻找比赛条件
【发布时间】:2013-11-01 23:49:07
【问题描述】:

有人能解释一下这段代码中的竞争条件吗?我的讲师设置了它,但我还不完全明白如何发现它们,或者说为什么会出现给出的结果。

public class SlowRace {

      public static void main(String args []) throws Exception {

          MyThread.count = 0 ;

          MyThread thread1 = new MyThread() ;
          thread1.name = "A" ;

          MyThread thread2 = new MyThread() ;
          thread2.name = "B" ;

          thread1.start() ;
          thread2.start() ;

          thread2.join() ;
          thread1.join() ;

          System.out.println("MyThread.count = " + MyThread.count) ;
      }
  }

  class MyThread extends Thread {

      volatile static int count ;

      String name ;

      public void run() {

          for(int i = 0 ; i < 10 ; i++) {
              delay() ;
              int x = count ;
              System.out.println("Thread " + name + " read " + x) ;
              delay() ;
              count = x + 1;
              System.out.println("Thread " + name + " wrote " + (x + 1)) ;
          }
      }

      static void delay() {

          int delay = (int) (1000000000 * Math.random()) ;
          for(int i = 0 ; i < delay ; i++) {}
      }
  } 

返回的结果:

Thread A read 0
Thread A wrote 1
Thread B read 0
Thread A read 1
Thread B wrote 1
Thread A wrote 2
Thread B read 2
Thread A read 2
Thread B wrote 3
Thread A wrote 3
Thread B read 3
Thread A read 3
Thread B wrote 4
Thread A wrote 4
Thread B read 4
Thread A read 4
Thread B wrote 5
Thread A wrote 5
Thread B read 5
Thread A read 5
Thread B wrote 6
Thread A wrote 6
Thread B read 6
Thread A read 6
Thread B wrote 7
Thread A wrote 7
Thread B read 7
Thread A read 7
Thread B wrote 8
Thread A wrote 8
Thread B read 8
Thread A read 8
Thread B wrote 9
Thread A wrote 9
Thread B read 9
Thread A read 9
Thread B wrote 10
Thread A wrote 10
Thread B read 10
Thread B wrote 11
MyThread.count = 11

【问题讨论】:

  • 你能扩展一下吗?
  • 'static int count' 不多说了 :)
  • @rob1994 我已经在真实答案中做到了

标签: java multithreading conditional-statements


【解决方案1】:

大家好,谁能解释一下这段代码中的竞争条件,

比赛在这两条线之间:

          int x = count ;
          ...
          count = x + 1;

一个线程获取该值,但另一个线程可以获取相同的值之前第一个线程用递增的值更新它。这就是比赛。

  1. thread-1 获取count 的值并将其存储在x 中。 x 是(假设是 10)。
  2. 同时thread-2也获取了count的值,存入xx 是(假设是 10)。
  3. thread-1 将x 递增为11 并将其存储回count
  4. thread-2 将其x 的副本递增为11 并将其存储回count——这将覆盖thread-1 的递增。

因此,count 不是 12,而是其中一个增量将丢失,它将是 11。

练习是指出增量不是原子的。真的不需要delay()count++ 也可以证明这个问题,因为它不是原子的(get/increment/set),并且线程可以在 3 个操作的中间被中断。

使这段代码复杂的一点是System.out.println(...) 是同步的,所以控制台输出会改变程序的时间。

【讨论】:

【解决方案2】:

您是在告诉编译器将信息存储在内存而不是缓存中。

volatile static int count ;

2 个线程同时运行。

  public void run() {

      for(int i = 0 ; i < 10 ; i++) {
          delay() ;
          int x = count ;
          System.out.println("Thread " + name + " read " + x) ;
          delay() ;
          count = x + 1;
          System.out.println("Thread " + name + " wrote " + (x + 1)) ;
      }
  }

想象一下。

count = 0;
Thread1(int x = count); //x = 0;
Thread1(delay)
Thread2(int x = count); //x = 0;
Thread2(delay)
Thread1(count = x + 1); //count = 1;
Thread2(count = x + 1); //count = 1; //While it has to be 2.

【讨论】:

    【解决方案3】:

    此逻辑是线程不安全的,因为 MyThread 类中静态变量 count 的更新不受保护。
    主线程将在启动后加入 Thread1 和 Thread2 并等待它们完成。然而,同时运行线程(线程 1,线程 2)的时间不吉利,最终可能会更新变量“计数”和相同的值。

    【讨论】:

    • 进入 for 块没有竞争。值的读取和写入之间存在竞赛。
    猜你喜欢
    • 1970-01-01
    • 2021-04-14
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 2010-11-05
    • 2018-06-14
    相关资源
    最近更新 更多