我对尚未理解的同步和易变性有所了解。
我理解一个线程可以在本地安全地更改。从我到目前为止所读到的是同步>挥发性的。
假设我有一个不长或双的参数,所以基本上是一个标准的整数(没有原子)。
我有一个同步方法,我用这个Integer做了很多工作。 所有线程都会获得此Integer的更新版本吗?或者我是否必须声明它是不稳定的?
public class stackoverflow {
private int x = 0;
public synchronized void rechnen(){
//dosomething
}
}
基本上在rechnen()完成后,我得到10000个线程,所有都会得到x的更新版本,因为我的方法是同步的?还是我必须宣布它是不稳定的?
答案 0 :(得分:5)
是的,他们将获得更新版本。 synchronized
保证两件事:变化和原子性的可见性。 volatile
只是保证变更的可见性。 Java保证同步块内的代码不会被优化(通过混合synchronized
块内外的命令),因此对于其中的变量的每次更改,在synchronized块结束后对所有线程都是可见的。
答案 1 :(得分:3)
是的,他们将获得更新版本,但前提是他们自己输入同步块。如果他们没有在同一个对象上输入同步块(锁定同一个监视器),则无法保证他们会看到更新。
如果您不希望其他线程进入同步块,则必须将变量声明为volatile。
答案 2 :(得分:2)
@partlov已经回答了你的问题,所以作为旁注,还有一些你可能想要考虑的事情。
将方法声明为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
}
}
}
在volatile
和synchronized
之间,存在大量用于特定并发目的的工具。其中大多数使用volatile
,synchronized
和CAS-operations的混合。例如,AtomicInteger为您提供了原子整数运算,其争用程度远低于synchronized
通常所见。所以尽量熟悉java.util.concurrent
答案 3 :(得分:1)
同步方法已在您的代码中使用。此外,您需要将x设置为易失性,如下所示
private volatile int x = 0;
这将确保访问此volatile字段的线程首先从主内存中读取其当前值,而不是使用潜在的CPU缓存值
因此,您可以确保代码是线程安全的
答案 4 :(得分:-1)
声明private volatile int x = 0;它将满足您的目的。为了更好地理解,请参阅AtomicInteger的实现。