非同步方法产生一致的结果

时间:2018-04-27 15:49:17

标签: java concurrency

我是Java的新手并且在玩线程。我编写了这个小程序来检查3个线程访问非同步方法时会发生什么:

class SharedValueHolder {
  public static int globalCounter = 0;
  public static void increment() {
    globalCounter++;
  }
}

class Incrementor implements Runnable {
  public void run() {
    for (int i = 0; i < 5; i++) {
      //reportValue();
      SharedValueHolder.increment();
    }
  }

  private void reportValue() {
    String threadName = Thread.currentThread().getName();
    System.out.println(threadName + " - " + SharedValueHolder.globalCounter);
  }
}

public class ThreadTest {
  public static void main(String... args) throws InterruptedException {
    runTest();
  }

  private static void runTest() throws InterruptedException {
    Thread thread1 = new Thread(new Incrementor());
    Thread thread2 = new Thread(new Incrementor());
    Thread thread3 = new Thread(new Incrementor());

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

    Thread.sleep(300);
    System.out.println(SharedValueHolder.globalCounter);
  }
}

令人惊讶的是,结果几乎总是15.有时我会得到14,但这非常罕见。

现在,如果我取消注释reportValue()中对Incrementor.run的调用,我会看到类似这样的内容:

Thread-2 - 0
Thread-1 - 0
Thread-0 - 0
Thread-0 - 3
Thread-0 - 4
Thread-0 - 5
Thread-0 - 6
Thread-1 - 2
Thread-1 - 8
Thread-1 - 9
Thread-1 - 10
Thread-2 - 1
Thread-2 - 12
Thread-2 - 13
Thread-2 - 14

这清楚地表明线程&#34;见&#34;在相同的时间相同的值,但结果仍然是正确的。有人可以向我解释这是如何运作的吗?

1 个答案:

答案 0 :(得分:2)

并发不是一个简单的主题,其中一个棘手的原因是因为有时你可能得到一个正确的结果(并认为你的代码是好的),但这并不意味着代码是真的很对它意味着给定你运行它的环境,线程的数量......它工作得很好。但它可能会在高度并发的环境中失败。

但是,你说你看到了相同的结果几乎总是,这并不总是如此。

它也是您问题的范围,仅包含5个元素的循环。可能第二个和第三个线程甚至在第一个线程结束时都没有开始。

但很容易看出它的错误。请尝试运行此示例:

class SharedValueHolder {
  public static int counter = 0;
}

class Incrementor implements Runnable {
  public void run() {
    for (int i = 0; i < 100000; i++) {
      SharedValueHolder.counter++;
    }
  }
}

public class ThreadTest {
  public static void main(String... args) throws InterruptedException {
    Thread thread1 = new Thread(new Incrementor());
    Thread thread2 = new Thread(new Incrementor());
    thread1.start();
    thread2.start();

    Thread.sleep(2000);
    System.out.println(SharedValueHolder.counter);
  }
}

两个线程增加100.000,所以你最终会期望200.000。但相反,我得到了:

102472
105560
121472
139343
120953