Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是";易挥发;方法中需要什么?_Java_Multithreading_Thread Safety - Fatal编程技术网

Java 是";易挥发;方法中需要什么?

Java 是";易挥发;方法中需要什么?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我已经读到,当线程访问变量时,应该使用volatile,以确保线程看到正确的值,但是当在方法中使用变量时,这是否也适用 示例代码: public class Limiter { int max = 0; public synchronized void doSomething() { max++; if(max < 10) System.out.println("Work"); Sy

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

示例代码:

public class Limiter
{
    int max = 0;

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

         System.out.println(max);
    }

}
公共类限制器
{
int max=0;
公共同步无效doSomething()
{
max++;
如果(最大值<10)
系统输出打印(“工作”);
系统输出打印项次(最大值);
}
}
可以安全地假设,如果多个线程调用
doSomething
,那么
max
将被设置为与前一个线程调用该方法时相同的状态吗


因为
doSomething()
是同步的,我知道只有一个线程可以修改
max
,但是当下一个线程调用它时会发生什么呢?
max
是否可以是不同的值,因为它不使用
volatile
?还是因为“Limiter”实例修改了它本身而安全呢?

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

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

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

这在许多方面都不准确*

首先:
volatile
只能用于字段。它不能用于其他类型的变量;i、 e.局部变量或参数。(原因:这将是毫无意义的,因为其他类型的变量只对一个线程可见。)

其次:
volatile
语义适用于是否从方法调用

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

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

public Counter {
    private volatile int count;

    public void increment() {
        // This is NOT correct.
        count++;
    }
}
上述示例不正确的原因是,
count++
不是原子的。实际上,它的意思是(字面上)
count=count+1
,另一个线程可以在当前线程访问它和写回更新值之间更改
count
。这将导致偶尔的增量损失

很容易看出,声明
max
volatile
并去掉
synchronized
关键字的代码版本也不正确,原因完全相同。您当前的版本在这方面更为正确。但是,它仍然不是完全正确的,因为没有任何东西可以阻止其他类(在同一个包中)访问或更新
max
。如果这是在另一个线程中完成的,那么您将有一个潜在的并发问题。。。除了泄漏的抽象之外


因此,要回答您的问题:

如果多个线程调用doSomething,那么max将被设置为与前一个线程调用该方法时相同的状态,这是否安全

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

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

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

max是否可以是不同的值,因为它不使用volatile

不。。。模块化泄漏抽象问题

还是因为“限制器”实例修改了它本身而安全

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


*至少,你对所读内容的总结是不准确的。据我们所知,你读的原文可能是正确的


更新


我读的部分是关于字段的(比如线程可以访问的变量)。很抱歉给你带来了困惑。我想知道的是,它是否也应用于线程调用的对象中的方法使用的所有变量

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


但是,需要注意的是,它仅适用于同步点。如果第二个线程没有正确同步,则所有赌注都将被取消。

我读的部分是关于字段的(如线程可访问的变量)。很抱歉给你带来了困惑。我想知道的是,它是否也应用于线程调用的对象中方法使用的所有变量