繁体   English   中英

方法中是否需要“易变”?

[英]Is “volatile” needed within methods?

我已经读过你应该在线程访问变量时使用volatile来确保线程看到正确的值,但是当在方法中使用变量时这也适用吗?

示例代码:

public class Limiter
{
    int max = 0;

    public synchronized void doSomething()
    {
         max++;
         if(max < 10)
             System.out.println("Work");

         System.out.println(max);
    }

}

假设如果一个多线程调用doSomething ,那么max是否可以安全地设置为与前一个Thread调用方法时相同的状态?

因为doSomething()是同步的,我知道只有一个线程可以修改max ,但是当下一个线程调用它时会发生什么? max可以是不同的值因为它不使用volatile吗? 或者是否安全,因为“限制器”实例会自行修改它?

volatile是字段声明的一部分,而不是其使用的一部分。 将局部变量声明为volatile是没有意义的,因为不同的线程不会看到局部变量。

在你的情况下,只要非同步方法中的代码没有访问max ,你就可以了 - 内存模型基本上确保只要所有代码获取/释放相同的监视器“保护”变量,所有线程都会看到一致的价值观。 (除了其他任何事情,每个线程在访问值之前必须获取监视器这一事实意味着一次只能有一个线程能够访问该值 - 你可以编写一个总排序“线程X让监视器在时间t0-t1,线程Y在时间t4-t5等时有监视器等

我已经读过你应该在线程访问变量时使用volatile来确保线程看到正确的值,但是当在方法中使用变量时这也适用吗?

这在许多方面都是不准确的*

首先: volatile只能用于字段。 它不能用于其他类型的变量; 即局部变量或参数。 (原因:它没有意义,因为其他类型的变量只对一个线程可见。)

其次:无论您是否从方法调用, volatile应用volatile语义。

第三: volatile是使用synchronized方法(或块)的替代方法。 但正确使用synchronized通常是使用同步构造执行的所有访问和更新的条件。 任何非同步访问或更新都可能导致程序(作为一个整体)不正确。

最后: volatile表示访问该字段将看到该字段值的最新值。 这不足以保证正确性 例如:

public Counter {
    private volatile int count;

    public void increment() {
        // This is NOT correct.
        count++;
    }
}

上面的例子不正确的原因是count++不是原子的。 它实际上意味着(字面上) count = count + 1 ,另一个线程可以在访问它的当前线程和写回更新值之间改变count 这会导致偶尔丢失增量。

很容易看出,由于完全相同的原因,声明maxvolatile并且摆脱synchronized关键字的代码版本将是不正确的。 在这方面,您当前的版本更正确。 但是,它仍然不完全正确,因为没有什么能阻止其他类(在同一个包中)访问或更新max 如果这是在不同的线程中完成的,那么除了漏洞抽象之外,你还有潜在的并发问题。


那么,回答你的问题:

假设如果一个多线程调用doSomething,那么max是否可以安全地设置为与前一个Thread调用方法时相同的状态?

不完全是因为抽象漏洞。 (声明max是私有修复此。)

因为doSomething()是同步的,我知道只有一个线程可以修改max,但是当下一个线程调用它时会发生什么?

synchronized块确保在同一对象上同步的下一个线程将看到这些更新。 (如何实现这一点是特定于平台......)

最大可以是不同的值因为它不使用volatile吗?

不...模糊漏洞抽象问题。

或者是否安全,因为“限制器”实例会自行修改它?

这个事实与此代码的线程安全性/正确性无关 重要的是同步,而不是自我修改。


*至少,您对所阅读内容的理解总结是不准确的。 据我们所知,您阅读的原始文本可能是正确的。


UPDATE

我读到的部分是讨论字段(如线程可访问的变量)。 对困惑感到抱歉。 我想知道的是它是否也适用于线程调用的对象中的方法使用的所有变量。

这适用于同步区域覆盖线程读取和/或写入的对象的所有字段。 实际上,它适用于其他对象的字段,以及在该区域中读/写的数组元素。 (对于非字段的变量,这是“没有实际意义”,因为没有其他线程可以看到它们。)

但是,需要注意的是,它仅适用于同步点。 如果第二个线程未正确同步,则所有投注都将关闭。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM