0

我认为我对使用关键字来防止java中线程之间的不一致有相当牢固的把握synchronized,但是我不完全理解如果不使用该关键字会发生什么。

例如,我有一个由两个线程访问/修改的字段:

private String sharedString = "";

class OneThread extends Thread {

  private Boolean mRunning = false;

  public OneThread() {}

  public synchronized setRunning(Boolean b) {
    mRunning = b;
  }

  @Override
  public void run() {
    while (mRunning) {
      // read or write to shared string
      sharedString = "text from thread 1";
      System.out.println("String seen from thread 1: " + sharedString);
      super.run();
    }
  }
}

class AnotherThread extends Thread {

  private Boolean mRunning = false;

  public AnotherThread() {}

  public synchronized setRunning(Boolean b) {
    mRunning = b;
  }

  @Override
  public void run() {
    while (mRunning) {
      // read or write to shared string
      sharedString = "text from thread 2";
      System.out.println("String seen from thread 2: " + sharedString);
      super.run();
    }
  }
}

由于这两个线程都在sharedString不使用同步关键字的情况下访问和修改字段,因此我预计会出现不一致。我想知道的是实际上发生了什么。在调试时,我在这种情况下仔细检查了两个线程,并注意到即使一个线程暂停,它的状态也可能是“粘滞的”。

对于上面的示例,假设两个线程都在调试器中暂停。如果我单步执行其中一个线程并让另一个暂停,我希望它会像单线程应用程序一样运行。然而,很多次在修改字段之后,访问它的下一行检索到“错误”值(与刚刚修改的值不一致的值)。

我知道这段代码不好..但我问这个问题是因为我希望有人能提供一个答案,让我们深入了解当多线程应用程序实施不佳时虚拟机中实际发生的情况。字段修改尝试不成功的线程是否有任何影响?

如果在糟糕地实现多线程代码之后,我们只是处于“未定义”行为的领域,并且学习这种行为没有任何价值,我可以接受......只是一个试图理解我的多线程菜鸟在调试器中观察。

4

2 回答 2

4

这是由于 Java 中跨线程同步的另一个关键功能:防止数据陈旧。作为 Java 内存模型的一部分,Java 线程可以缓存共享数据的值。除非在同步块中访问共享的可变数据或将其标记为易失性,否则无法保证线程将看到另一个线程进行的更新。请参阅此处了解更多信息。

于 2012-09-23T22:30:20.683 回答
0

如果没有其他线程可以更改共享值(如果真的只有 2 个线程并且一个肯定被暂停,情况就是这样),打印输出真的没有办法是“错误的”。您能否提供“启动”这两个线程(即您的主线程)的代码?

于 2012-09-23T23:20:52.063 回答