Java 同步如何帮助可变可见性?

Java 同步如何帮助可变可见性?,java,multithreading,synchronization,Java,Multithreading,Synchronization,根据“实践中的Java并发”,它可能会打印0,因为在写入一个数字或程序之前,读线程可能会看到write to ready,因为它没有使用足够的同步,所以程序永远不会终止。不能保证主线程写入的ready和number的值对读线程可见 怎么可能呢?程序将由一个线程按顺序运行,它首先写入number,然后写入ready变量。不是吗?这个程序怎么可能永远循环?不能保证通过更改一个线程中的变量,其他线程将看到这些更改的结果。从技术上讲,它们之间没有“先发生后发生”的关系,因此没有任何保证(而在实践中,您几

根据“实践中的Java并发”,它可能会打印0,因为在写入一个数字或程序之前,读线程可能会看到write to ready,因为它没有使用足够的同步,所以程序永远不会终止。不能保证主线程写入的ready和number的值对读线程可见


怎么可能呢?程序将由一个线程按顺序运行,它首先写入number,然后写入ready变量。不是吗?这个程序怎么可能永远循环?

不能保证通过更改一个线程中的变量,其他线程将看到这些更改的结果。从技术上讲,它们之间没有“先发生后发生”的关系,因此没有任何保证(而在实践中,您几乎随时都会看到变化)

这就是线程可能永远运行的原因

第二,为什么有时0

嗯,报纸上说

在一个线程中写入数据,而在另一个线程中读取数据 例如,线程可能看起来与这些读取的顺序不符

这意味着你的

public class NoVisibility {
   private static boolean ready;
   private static int number;
   private static class ReaderThread extends Thread {
      public void run() {
         while (!ready)
            Thread.yield();
         System.out.println(number);
      }
   }

   public static void main(String[] args) {
       new ReaderThread().start();
       number = 42;
       ready = true;
   }
}
可以以任何顺序发生。现在他们很可能会按顺序出现,但同样没有保证

您可以通过将变量更改为volatile来修复它,在这种情况下,写入的内容将始终对读者可见,或者通过将您在其中修改状态的代码设置为关键部分(参见本书)。总的来说,我觉得使用太多易失性变量有点麻烦,所以你应该尽量少用它们,比如线程“运行”变量

number = 42;
ready = true;

如果ready未标记为“volatile”,则ReaderThread可能会检查其值(为0)。 它稍后不会再次检查ready的值,因为它假定它没有更改


volatile关键字指示编译器根本不要有这样的假设,并且变量的值可能会在他脚下发生变化。

为什么使用太多volatile变量会出现问题?或者与此相关的问题是,为什么我们不能用volatile变量替换同步代码?因为volatile不会“拉伸”代码块。单个变量的原子突变是可以的,但对多个变量的访问不能被视为单个原子操作。volatile不会在代码块之间“拉伸”——很抱歉,我没有理解这一点。你能解释一下吗?另外,我不明白访问多个变量如何在单个原子操作中导致问题。volatile有点像只同步一个变量。如果您有多个VAR需要同步在一起,那么它将无法工作。考虑一下从一个银行账户转到另一个账户。您需要“锁定”两个帐户的访问权限。Volatile不会这么做。为什么使用太多Volatile变量会有问题?或者与此相关的问题是,为什么我们不能用可变变量替换同步代码?
public class NoVisibility {
    private static volatile boolean ready;
    private static volatile int number;

    private static class ReaderThread extends Thread {
        public void run() {
            while (!ready)
                Thread.yield();
            System.out.println(number);
        }
    }

    public static void main(String[] args) {
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}