易失性和同步

时间:2015-12-30 10:32:07

标签: java multithreading synchronized volatile

我对尚未理解的同步和易变性有所了解。

我理解一个线程可以在本地安全地更改。从我到目前为止所读到的是同步>挥发性的。

假设我有一个不长或双的参数,所以基本上是一个标准的整数(没有原子)。

我有一个同步方法,我用这个Integer做了很多工作。 所有线程都会获得此Integer的更新版本吗?或者我是否必须声明它是不稳定的?

public class stackoverflow {

    private int x = 0;

    public synchronized void rechnen(){ 
        //dosomething   
    }
}

基本上在rechnen()完成后,我得到10000个线程,所有都会得到x的更新版本,因为我的方法是同步的?还是我必须宣布它是不稳定的?

5 个答案:

答案 0 :(得分:5)

是的,他们将获得更新版本。 synchronized保证两件事:变化和原子性的可见性。 volatile只是保证变更的可见性。 Java保证同步块内的代码不会被优化(通过混合synchronized块内外的命令),因此对于其中的变量的每次更改,在synchronized块结束后对所有线程都是可见的。

答案 1 :(得分:3)

是的,他们将获得更新版本,但前提是他们自己输入同步块。如果他们没有在同一个对象上输入同步块(锁定同一个监视器),则无法保证他们会看到更新。

如果您不希望其他线程进入同步块,则必须将变量声明为volatile。

答案 2 :(得分:2)

@partlov已经回答了你的问题,所以作为旁注,还有一些你可能想要考虑的事情。

不要将synchronized用作修饰符

将方法声明为synchronized时,它使用监视器。在Java中,每个Object碰巧都是一个监视器,在这种情况下使用了类实例。所以你的例子会有效地变成:

public void rechnen(){ 
    synchronized(this) {
        //dosomething
    }   
}

现在这会造成潜在的问题,因为您的显示器正在泄漏。应用程序的其他部分可以使用同一个监视器同步完全不相关的代码,这些代码可能导致/导致性能下降,或者更糟糕的是,当它相关时可能导致意外的死锁。

因此,主要建议是始终保持监视器的私密性。如下所示:

public class stackoverflow {
    private final Object monitor = new Object();
    private int x = 0;

    public void rechnen(){
         synchronized(monitor) {
            //dosomething
         } 
    }
}

知道你的Api

volatilesynchronized之间,存在大量用于特定并发目的的工具。其中大多数使用volatilesynchronizedCAS-operations的混合。例如,AtomicInteger为您提供了原子整数运算,其争用程度远低于synchronized通常所见。所以尽量熟悉java.util.concurrent

答案 3 :(得分:1)

同步方法已在您的代码中使用。此外,您需要将x设置为易失性,如下所示

private volatile int x = 0;

这将确保访问此volatile字段的线程首先从主内存中读取其当前值,而不是使用潜在的CPU缓存值

因此,您可以确保代码是线程安全的

答案 4 :(得分:-1)

声明private volatile int x = 0;它将满足您的目的。为了更好地理解,请参阅AtomicInteger的实现。

相关问题