易失性或对原语类型同步?
-
21-09-2019 - |
题
在Java中,分配是原子,如果变量的大小小于或等于32位,但并不如果多于32位。
什么(易失性/同步)会更有效双或长分配的情况下使用?
像,
volatile double x = y;
同步是不适用与原始参数。如何在这种情况下使用同步?当然,我不希望我的锁类,所以this
不宜使用。
解决方案
如果您发现锁本身太重,然后同步的对象是要走的路。在此之前的Java 1.5挥发性可能是一个不错的选择,但现在波动可以通过强制在哪里分配情况的方法指令排序非常大的影响。设置或获取该双值时创建一个单独的对象(private final Object X_LOCK = new Object();
)和同步就可以了。这会给你越过锁紧,这似乎是你需要控制的精细程度。
在新的并发包有更多的选项,如的AtomicReference其可以是很好的替代挥发性如果确实需要,以避免同步。
其他提示
你到底想干什么?的synchronized
和volatile
关键字是Java机制,其可用于确保一致的值由不同的线程读取相同数据中观察到。特别是他们让你推理的之前发生的在你的程序的关系。
您根本无法避免使用为了volatile
或synchronized
之一在多线程程序适当地访问非final
字段。这就是说,主要的原因,你可能需要在synchronized
volatile
是利用原子的要求的比较和集的操作(即它不会有任何性能考虑)。例如,在多线程程序:
volatile int i = 0;
public void foo() {
if (i == 0) i = i + 1;
}
上面的代码具有固有的不安全,即使该变量的声明作为易失性单元,其读取和写入被刷新到主存储器 - 唯一的安全实施这样的方法将是这样的:
int i = 0;
public synchronized void foo() {
if (i == 0) i = i + 1;
}
所以,你应该更喜欢哪个?那么,如果有多个线程修改字段依赖于该字段的值(即比较并集),则synchronized
是唯一的安全解决方案。
这也是值得一说的: synchronized
的性能开销是没有问题(适用于绝大多数情况下)。同步性能问题通常是由于不必要的代码瓶颈,死锁或活锁,如果需要可以缓解。任何纯时钟周期开销将通过其他的东西被矮化你应用程序执行:文件IO,数据库查询,远程处理等
挥发性肯定是去,如果你只是做一个分配的方式。 我敢肯定,你知道的,但因为它被带到了:如果你想这样做更复杂的操作(递增例如值),你将需要syncrhonize。我++是永远不会对任何类型的变量是线程安全的。你需要同步。我++等,因为,实际上是大于1项的操作。
不:有人表示,你可以使用AtomicDouble,但目前还没有AtomicDouble在java.util.concurrent.atomic中
如果你正在做X上的一个多个操作,需要在年底将其设置为一个新值,有可能没有锁定什么那么这样做在一个线程安全的方式,并将它是线程安全的,利用比较和设置。例如:
AtomicLong x = new AtomicLong(SomeValue);
public void doStuff() {
double oldX;
double newX;
do {
oldX = x.get();
newX = calculateNewX(oldX);
} while (!x.compareAndSet
(Double.doubleToLongBits(oldX), Double.doubleToLongBits(newX)));
这个作品,因为compareAndSet会看看,因为你读它最后一次x的值发生了变化。如果x已经改变,那么你被迫做一遍计算和重新尝试设置它。
您当然可以实现的,而不是做这些doubleToLongBits的转换自己的AtomicDouble。看一看AtomicFieldUpdater。
KDSRathore,可以使用一些明确的锁,或者使一些虚拟对象对象=新的对象(),在其上您同步双
的在设定器/吸气剂