有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java并发编程,线程间共享值

我是并发编程的初学者,我想确切地理解为什么当我在get()中注释sleep(1)时,这个程序没有结束 我的第一个想法是,睡眠(1)将手放回Main线程,也许忙碌的等待与此有关

public class Rdv<V> {
  private V value;

  public void set(V value) {
    Objects.requireNonNull(value);
    this.value = value;
  }

  public V get() throws InterruptedException {
    while(value == null) {
        Thread.sleep(1);  // then comment this line !
    }
    return value;
  }

  public static void main(String[] args) throws InterruptedException {
    Rdv<String> rendezVous = new Rdv<>();
    new Thread(() -> {
      try {
        Thread.sleep(5000);
      } catch (InterruptedException e) {
        throw new AssertionError(e);
      }
      rendezVous.set("hello");
    }).start();

    System.out.println(rendezVous.get());
  }
}

共 (1) 个答案

  1. # 1 楼答案

    首先也是最重要的一点是,这个计划被严重破坏了。即使在睡眠状态下,也不能保证它会终止。可能会,但可能不会

    问题在于,value字段不是易失性的,并且在获取/设置值时不使用synchronized或其他锁。这意味着不能保证一个线程会看到另一个线程的变化!应该停止程序的write-to值对于正在等待的线程可能永远都不可见。有了睡眠,一切正常,因为Java是在解释模式下运行的。没有睡眠,即时编译器就有时间启动并优化代码。它发现while循环可以被重写为一个更高效的版本,它可以做同样的事情:永远循环。这就是它的作用

    最简单的修复方法是将value字段声明为volatile。然后Java知道它可能会改变,并避免优化读取

    短版本,除非您很了解Java内存模型,否则始终同步对线程之间共享的数据的访问。安全总比后悔好