易变和同步

Volatile and Synchronized

关于 synchronized 和 volatile,我还有些不明白。

我了解线程可以在本地安全更改。到目前为止我读到的是 synchronized > volatile.

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

我有一个同步方法,我用这个整数做了很多工作。 所有线程都会得到这个 Integer 的更新版本吗?或者我是否也必须将其声明为 volatile?

public class Whosebug {

    private int x = 0;

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

基本上在 rechnen() 完成后,我有 10000 个线程,因为我的方法是同步的,所以都会得到 x 的更新版本吗?还是我也必须将其声明为 volatile?

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

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

如果不想让其他线程进入synchronized块,那么就要声明变量为volatile

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

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

不要使用 synchronized 作为修饰符

在将方法声明为同步时,它使用监视器。在 Java 中,每个 Object 恰好是一个监视器,在这种情况下使用 class 实例。所以你的例子在情感上变成了:

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

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

所以主要的建议是,始终保持您的显示器的私密性。所以像这样:

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

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

了解你的Api

volatilesynchronized 之间,有大量用于特定并发目的的工具。其中大部分混合使用 volatilesynchronizedCAS-operations. For instance AtomicInteger gives you atomic integer operation with far less contention as is usually seen by the of synchronized. So try to get really familiar with java.util.concurrent