2017-04-08 46 views
4

我想知道如果一个私人布尔字段的getter方法强制其他线程获取最新的更新值?这是挥发性领域的替代品吗? 例如:getter方法是Java中volatile的替代方法吗?

Class A { 
    private boolean flag; 

    public boolean getFlag() { 
     return this.flag; 
    } 

    public void setFlag(boolean flag) { 
     this.flag = flag; 
    } 
} 

VS

Class B { 
    public volatile boolean flag; 
} 

编辑:这是真的,整个对象是由一个线程(包括私营领域)的缓存,这样,当我打电话,吸气它会返回缓存的私人领域?

+4

号这两个是等效没有办法。你为什么会认为他们是?从逻辑上讲,如果'volatile'与getter相同,那么为什么我们需要一个全新的语言关键字呢? –

+0

正如我所说,我认为getter强制线程获得未缓存的值。为什么不吸取最后一次更新的值? –

+0

也许您需要查看[JLS](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4)。 –

回答

3

不,吸气不会造成现场进行同步。

谈论在多线程环境下读取和写入原始的时候,我们有三个问题,造成CPU

  1. 原子性:它可能需要存储或加载运行一个以上的汇编指令,例如,在32位CPU上写入一个64位整数。当前线程可能会被操作系统在指令序列的中间置于睡眠状态。
  2. 可见性:在一个内核上运行的线程可能无法读取来自其他内核的其他线程写入的最新值。只是因为CPU这么说。
  3. 重新排序:为了使程序运行得更快,CPU按照它认为合适的方式混合了汇编指令的顺序。

Getter不能解决任何这些问题。即使它是,JIT编译器可能会完全优化该功能。那又如何?

挥发性是解决上述问题的方法之一。锁也是如此。它们确保一个线程读取原语的最新值,或者确保写入的值对其他线程可见。它们还会使汇编指令按照编译的原样运行,而不会进行任何混合。

作为一个附注,生成的程序集可能与您在代码中编写的程序完全不同。你问自己:“我在我的代码中写道从flag中读取,那么为什么程序不能从字段本身读取?”编译器可以做任何它认为合适的组件来尽可能快地组装。通过而不是添加了任何锁定或易失性说明符,您基本上告诉编译器不涉及多线程访问,并且编译器(以及随后的CPU)可以自由地假定该对象未被多个线程触及。它可能是这个对象可能不是在第一个地方创建的。 JIT编译器可能会说“好吧,将这个布尔值声明为一个寄存器并将其视为整个对象”。这是非常可能的。

编辑:整个对象是否被一个线程(包括私有字段)缓存是真的,这样当我调用getter时它会返回缓存的私有字段?

你不能这样假设。它取决于JVM,底层操作系统和底层CPU。它可能完全缓存,部分或根本不缓存。提醒你,即使对象被高速缓存,大部分CPU的外部都有多个高速缓存行,它在哪里被高速缓存?在寄存器或其中一个缓存行中?

+0

“_Java解决了第一个问题_” - 请参阅[JLS 17.6](https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.6);读取和写入非易失性64位值不保证是原子性的。 –

+0

@BoristheSpider让我更新我的回答 –

+0

@BoristheSpider也是,无法保证空间呢? –

0

getter强制线程获取未缓存的值?这是挥发性领域的替代品吗?

没有,getter方法不强求什么,所以你必须需要一个volatile使当前线程看到由其他线程更新的最新值,否则,你可能会看到过时的值。

您需要知道here以下的文字,并清楚地理解原子访问的概念。

volatile变量对其他线程始终可见。这 也意味着,当一个线程读取volatile变量,它认为没有 只是最新的变化挥发

+0

是不是应该得到真正价值的吸气方法?或者是整个对象被缓存(包括私有字段),所以当我调用getter时它会返回缓存的私有字段? –

+1

@ ovidiu-miu“getter”并不是特别的。这只是一种方法,就像任何其他方法一样。它需要参数并返回一个值。当一个变量被多个线程读取时,这些读取可能不一致。句号。 –

1

我想知道如果一个私人布尔字段一个getter方法迫使其他线程,以获得最新更新值

号它不会强迫其他线程获得在没有最新值volatile的关键字。

这是一个替代挥发性领域?

号简单的getter呼叫不是替代得到没有volatile关键字boolean值的最新值。

更好的解决方案解决你的问题:使用AtomicBoolean

可以用原子方式更新的boolean值。有关原子变量属性的描述,请参阅java.util.concurrent.atomic包规范。

很少有更多有用的链接:

Atomic package-summary

What is the difference between atomic/volatile/synchronized?