17

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

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

像,

  volatile double x = y;

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

4

5 回答 5

25

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

您根本无法避免使用volatileorsynchronized之一来正确访问final多线程程序中的非字段。也就是说,您可能需要synchronizedover的主要原因是需要volatile使用原子比较和设置操作(即,它不会考虑任何性能)。例如,在多线程程序中:

volatile int i = 0;

public void foo() { 
    if (i == 0) i = i + 1;
}

上面的代码本质上是不安全的,即使变量的声明为 volatile 意味着读取和写入被刷新到主内存 - 这种方法的唯一安全实现是这样的:

int i = 0;

public synchronized void foo() {
    if (i == 0) i = i + 1;
}

那么你应该更喜欢哪个?好吧,如果您有多个线程根据该字段的值修改一个字段(即比较和设置),那么synchronized这是唯一安全的解决方案。

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

于 2009-11-22T17:05:14.957 回答
5

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

在新的并发包中有更多选项,例如 AtomicReference 如果您确实需要避免同步,它可能是 volatile 的一个很好的替代品。

于 2009-11-22T17:11:41.020 回答
3

如果你只是做一个任务, volatile 肯定是要走的路。我相信你知道,但是自从它被提出:如果你想做更复杂的操作(例如增加值),你需要同步。i++ 对于任何类型的变量都不是线程安全的。你需要同步。i++ 之类的,因为这实际上不止 1 次操作。

不是:有人表示可以使用 AtomicDouble,但 java.util.concurrent.atomic 中目前没有 AtomicDouble

如果您在 x 上执行多项操作,这需要在最后将其设置为新值,则可以以线程安全的方式执行此操作,而无需任何锁定,并使其成为线程安全的,使用 compare 和放。例子:

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)));

This works because compareAndSet will see if the value of x has changed since the last time you read it. If x has changed then you are forced to do the computation over again and re-try setting it.

You could of course implement your own AtomicDouble instead of doing these doubleToLongBits conversions. Take a look at AtomicFieldUpdater.

于 2009-11-23T11:15:25.017 回答
2

KDSRathore,您可以使用一些显式锁,或制作一些虚拟 Object object = new Object() ,您可以在该双精度的 setter/getter 中同步

于 2009-11-22T17:06:57.507 回答
1

According to the oracle documentation, you can use volatile to refer to Double object:

volatile Double x = y;

"Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values."

于 2017-12-08T11:26:20.467 回答