易失性和同步

Tim*_* N. 3 java multithreading volatile synchronized

我还有一些关于同步和不稳定的东西.

我理解一个线程可以在本地安全地更改.从我到目前为止所读到的是synchronized> volatile.

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

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

public class stackoverflow {

    private int x = 0;

    public synchronized void rechnen(){ 
        //dosomething   
    }
}
Run Code Online (Sandbox Code Playgroud)

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

par*_*lov 5

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

  • _...其中变量的每个更改,在同步块结束后对所有线程都可见。_ 不完全正确。JLS 仅保证如果线程 A 更新变量然后退出同步块,那么线程 B 将能够在线程 B 在同一对象上同步之后看到更新。_ (2认同)

M P*_*oet 5

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

不要使用synchronized作为修饰符

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

public void rechnen(){ 
    synchronized(this) {
        //dosomething
    }   
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    public void rechnen(){
         synchronized(monitor) {
            //dosomething
         } 
    }
}
Run Code Online (Sandbox Code Playgroud)

了解你的 API

volatile和之间synchronized有大量用于特定并发目的的工具。其中大多数混合使用volatilesynchronizedCAS 操作。例如,AtomicInteger为您提供原子整数操作,并且争用要少得多,正如 of 通常所看到的那样synchronized。所以尝试真正熟悉java.util.concurrent