【问题标题】:Is a volatile variable shared by all instances of an object?一个 volatile 变量是否由对象的所有实例共享?
【发布时间】:2017-03-27 16:11:27
【问题描述】:

我有一个实现游戏的 java 应用程序。

负责整个游戏的类也实现了Runnable接口,并重写了run方法,实现了玩游戏的过程。此 run() 方法包含一个循环,该循环将继续运行,直到将 private volatile boolean endThread 设置为 true。这将通过一个名为 stop() 的方法完成,其中 endThread 设置为 true。

我希望能够从我的 main 方法中停止特定线程,调用 stop() 来结束正在玩游戏的特定线程,结束线程。

public class Game implements Runnable{
  private volatile boolean endThread;

  public Game(){
    endThread = false;
  }

  public void run(){
    while(endThread != true){
      // insert code to simulate the process of running the game
    }
    System.out.println("Game ended. Ending thread.");
  }

  public void stop(){ 
    endThread = true;
  }
}

public class Main{
  public static void main(String[] args){
    Game gameOne = new Game();
    Thread threadOne = new Thread(gameOne);
    threadOne.start();
    Game gameTwo = new Game();
    Thread threadTwo = new Thread(gameTwo);
    threadTwo.start();
    threadTwo.stop(); // will this stop threadOne aswell?
  }
}

我想知道的是,如果变量是 volatile,游戏类的每个实例是否会共享同一个 endThread 变量,这样当使用 stop() 停止一个线程时,所有其他线程也会停止?

【问题讨论】:

  • no - volatile 仅表示从标记为 volatile 的变量中写入和读取是原子的,而不是更少,而不是更多
  • “... volatile 修饰符保证任何读取字段的线程都会看到最近写入的值。” - 乔什布洛赫。所以,没有不共享。
  • @bag 您将可见性(易失性给出)与共享性(静态给出)混淆了。如果你想让所有线程都看到变量的最新值,它需要是 volatile 的。
  • @AndyTurner 通过“所有线程看到变量的最新值”,你的意思是每个线程都会看到真正的最新值,如从 main 方法设置,该特定线程游戏类中的变量?还是说所有线程都能看到同一个变量的值?
  • @bag 每个线程都有它的 own 实例(它没有 static 修饰符)。所以当你调用stop时,只有那个特定的线程会看到值是true

标签: java multithreading volatile


【解决方案1】:

这里确实需要 volatile 修饰符,因为它引入了可见性。如果你删除volatile,你可能永远看不到更新的值,volatile 关键字将确保一旦写入,其他线程可以看到它。

您感到困惑的是 static 这里是 per-class 而不是 per-instance

有一篇必读文章here

【讨论】:

  • 啊,我想我明白了。游戏类的每个实例都会有自己的endThread,但是volatile修饰符会允许变量被写入main()并从main()中改变,这样在run中循环的终止条件下才会真正从主存中检查(),并结束该特定线程。这是正确的吗?
  • @bag 是的,它不是 真的 来自主内存,但你可以这样想(它是一个缓存一致性协议,它执行 sync 以便所有线程看到一致的世界观)。
  • 不,@bag,这并不完全正确。每个线程共享endThread 变量,但有自己的视图。如果变量未共享,则无法在线程之间传输数据。所以当线程A修改endThread时,其他线程可能会看到变化,如果使用适当的同步肯定会看到变化。
  • @LewBloch 因此,如果我要从 main 方法更改线程 A 中的变量以停止线程 A,是否也会停止线程 B、C、D 等,因为它们是同一类的所有实例?
  • 如果线程是从一个类Foo 的同一个实例启动的,你还没有向我们展示,它们将共享该Foo 对象的所有实例变量。所有线程都在Thread 的实例中运行,但我不确定说线程是任何类的实例是否正确。当然,线程是 Foo 的实例是不正确的,它是创建它的实例的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 2021-07-04
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
相关资源
最近更新 更多