基元类型的易失性还是同步?

在 Java 中,如果变量的大小小于或等于 32 位,则赋值是原子的,但如果大于 32 位,则赋值不是原子赋值。

在双重或长分配的情况下,使用哪种(易失性/同步)更有效?

喜欢

  volatile double x = y;

synchronized 不适用于基元参数。在这种情况下,如何使用同步?当然,我不想锁定我的类,所以不应该使用。this


答案 1

你想做什么?和 关键字是 Java 中的机制,可用于确保读取相同数据的不同线程观察到一致的值。特别是,它们允许您推理程序中发生之前的关系。synchronizedvolatile

您根本无法避免使用其中一个或为了正确访问多线程程序中的非字段。也就是说,您可能需要over的主要原因是需要使用原子比较和集合操作(即它不会是任何性能考虑因素)。例如,在多线程程序中:volatilesynchronizedfinalsynchronizedvolatile

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

同样值得一提的是:同步的性能开销不是问题(在绝大多数情况下)。同步性能问题通常是由于不必要的代码瓶颈、死锁或活锁引起的,如有必要,可以缓解这些问题。任何纯时钟周期开销都将与应用程序所做的其他事情相形见绌:文件IO,数据库查询,远程处理等。


答案 2

如果您发现锁定对象本身太重,那么同步就是要走的路。在 Java 1.5 之前,易失性可能是一个不错的选择,但现在易失性可以通过对发生赋值的方法强制指令排序来产生非常大的影响。创建一个单独的对象 (),并在设置或获取该双精度值时对其进行同步。这将使您对锁定进行精细的控制,这似乎是您需要的。private final Object X_LOCK = new Object();

在新的并发包中,有更多的选项,例如 AtomicReference,如果您确实需要避免同步,这可能是易失性的良好替代品。