除了类变量之外的对象的波动性

Abh*_*ang 6 java concurrency multithreading volatile

我曾经认为,在两个线程之间共享的任何变量都可以在线程本地缓存,并且应该声明为volatile.但这种信念最近遭到了队友的挑战.我们试图弄清楚在下列情况下是否需要挥发性物质.

class Class1
{
   void Method1()
   {
      Worker worker = new Worker();
      worker.start();
      ...
      System.out.println(worker.value); // want to poll value at this instant
      ...
   }

   class Worker extends Thread
   {
      int value = 0; // Should this be declared as a volatile?
      public void run()
      {
         ...
         value = 1; // this is the only piece of code that updates value
         ...
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

现在我的论点是,有可能Worker(子)线程可以缓存线程中Worker对象的变量"value",并在将值设置为1时更新它的副本.在这种情况下,主线程可能看不到更新的值.

但是我的队友认为,由于对"值"的访问是通过对象(worker)进行的,因此两个线程都可以看到不同的值,只有两个线程都维护"worker"对象本身的单独副本才有可能. (这将进一步意味着创建线程涉及创建所有共享对象的深层副本).

现在我知道这不可能是真的,因为每个线程维护所有共享对象的完全不同的副本是非常低效的.因此,我非常怀疑.在主线程中执行"worker.value"是否引用了与在子线程中执行"this.value"不同的内存位置?子(Worker)线程会缓存"值"吗?

问候.

Gra*_*ray 7

现在我的论点是,有可能Worker(子)线程可以在本地缓存Worker对象线程的变量"value",并在将值设置为1时更新它的副本.在这种情况下,主线程可能看不到更新的值.

你是对的.即使您正在处理相同的Worker实例,也无法保证Worker已在各种不同的线程内存缓存之间同步了字段的缓存内存版本.

value必须将该字段标记为volatile保证其他线程将看到value = 1;value字段的更新.

但是我的队友认为,由于对"值"的访问是通过对象(worker)进行的,因此两个线程都可以看到不同的值,只有两个线程都维护"worker"对象本身的单独副本才有可能. ...

不,这不正确.线程内存的棘手部分围绕处理器内存缓存.如果没有强加的内存屏障,volatile进程可以完全自由地缓存内存.因此,即使两个线程都使用相同的实例Worker,它们也可能具有与之关联的内存的本地缓存副本Worker.

线程架构得到了很大的速度,因为它们使用独立的高速处理器本地内存,而不是始终引用中央存储.

  • 另一种思考这个问题的方法......因为`worker`可以随时改变`value`,独立地与其他线程的视图不一致,内存模型*允许*`worker`拥有它自己的视图`值`作为性能优化.你需要volatile来明确地说你打算让两个线程拥有这个变量的一致视图.这改变了所允许的 - 现在每个读取都需要首先同步内存. (2认同)