Volatile or synchronized for primitive type?
Asked Answered
M

5

18

In Java, assignment is atomic if the size of the variable is less than or equal to 32 bits but is not if more than 32 bits.

What (volatile/synchronized) would be more efficient to use in case of double or long assignment?

Like,

  volatile double x = y;

synchronized is not applicable with primitive argument. How do I use synchronized in this case? Of course I don't want to lock my class, so this should not be used.

Mechanist answered 22/11, 2009 at 17:2 Comment(5)
Why do you "not want to lock [your] class"? (Note that the lock on an instance method is only taken out on the object itself). Note also that modern JVM's are extremely advanced and the performance overhead of synchronization is usually not an issueElatia
I have a jsp where many people access/update the data. data is in a cache object and there I need these synchronizations and et al because number of people could be numerous.Mechanist
I think i should go with AomicDouble.Mechanist
Wasn't volatile added to Java pretty much only to make double-checked locking work right?Quartus
@kts No, volatile has been in Java from the start, but they did change/fix the memory model in Java 5.Mayotte
A
5

If you find locking on the object itself too heavy, then synchronized is the way to go. Prior to Java 1.5 volatile may have been a good choice, but now volatile can have a very large impact by forcing instruction ordering on the method where the assignment happens. Create a separate object (private final Object X_LOCK = new Object();) and synchronize on it when setting or getting the value of that double. This will give you a fine level of control over the locking, which it seems that you need.

In the new concurrency package there are more options, such as AtomicReference which may be a good replacement for volatile if you really need to avoid synchronization.

Amorous answered 22/11, 2009 at 17:11 Comment(2)
@Pacerier, it really depends (@Elatia hits the performance point quite well), but it does have a larger impact now (with 1.5 and greater) than it used to, and it is possible to be more minimalistic. In practice, this would have to be some pretty heavily used code with lots of contention and good opportunities for instruction re-ordering to matter. So it is not a worthwhile performance optimization without evidence that is a problem in your specific case (there are really very few things that are).Amorous
Synchronizing on an Object has the same happens-before ordering semantic.Ancelin
E
25

What are you trying to do? The synchronized and volatile keywords are mechanisms in Java which can be used to ensure that consistent values are observed by different threads reading the same data. In particular they allow you to reason about happens-before relations in your programs.

You simply cannot avoid using one of volatile or synchronized in order to properly access non-final fields in a multi-threaded program. That said, the main reason that you are likely to require synchronized over volatile is the requirement for using atomic compare and set operations (i.e. it will not be any performance consideration). For example, in a multi-threaded program:

volatile int i = 0;

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

The above code is inherently unsafe, even though the variable's declaration as being volatile means that reads and writes are flushed to main memory - the only safe implementation of such a method would be something like:

int i = 0;

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

So which should you prefer? Well, if you have multiple threads modifying a field dependent on that field's value (i.e. compare-and set), then synchronized is the only safe solution.

It's also worth saying: the performance overhead of synchronized is not a problem (in the overwhelming majority of cases). Synchronization-performance issues are usually due to unnecessary code bottlenecks, deadlocks or livelocks and can be mitigated if necessary. Any pure clock-cycles overhead will be dwarfed by other things you application does: file IO, database queries, remoting etc.

Elatia answered 22/11, 2009 at 17:5 Comment(7)
Volatile isn't safe even for just i++ if i is double or long.Conformity
Yes, but which one I should prefer in such cases.Mechanist
My point was about compare-and set; if (i ==0) i++ is not safe, even when i is an intElatia
@DKS - as my answer says, volatile is useless in the case of a compare-and-set. It's my observation that this is the vast majority of casesElatia
+1 for comments about performance. Don't prematurely optimise!Fianna
@oxbow_lakes: Care to explain these statements: - "performance overhead of synchronization is usually not an issue" - "the performance overhead of synchronized is not a problem"Ganges
@Ganges - well, many applications will have overheads that dwarf any extra time spent in synchronization (i.e. the overhead of actually obtaining the mutex). I'm think of disk I/O, database access, network communication etc. That is why I qualified the statement with "in the vast majority of cases". Furthermore, modern VMs can do a lot in terms of lock elision which genuinely mean that in the absence of contention, synchronization has almost zero overhead.Elatia
A
5

If you find locking on the object itself too heavy, then synchronized is the way to go. Prior to Java 1.5 volatile may have been a good choice, but now volatile can have a very large impact by forcing instruction ordering on the method where the assignment happens. Create a separate object (private final Object X_LOCK = new Object();) and synchronize on it when setting or getting the value of that double. This will give you a fine level of control over the locking, which it seems that you need.

In the new concurrency package there are more options, such as AtomicReference which may be a good replacement for volatile if you really need to avoid synchronization.

Amorous answered 22/11, 2009 at 17:11 Comment(2)
@Pacerier, it really depends (@Elatia hits the performance point quite well), but it does have a larger impact now (with 1.5 and greater) than it used to, and it is possible to be more minimalistic. In practice, this would have to be some pretty heavily used code with lots of contention and good opportunities for instruction re-ordering to matter. So it is not a worthwhile performance optimization without evidence that is a problem in your specific case (there are really very few things that are).Amorous
Synchronizing on an Object has the same happens-before ordering semantic.Ancelin
U
3

volatile is certainly the way to go if you are only doing an assignment. I'm sure you know, but since it was brought up: if you would like to do more complex operations (increment the value for example) you would need to syncrhonize. i++ is never thread safe for any type of variable. You need to synch. i++ and the like since that is actually more than 1 operation.

Not: It was expressed that you could use AtomicDouble but there is currently no AtomicDouble in java.util.concurrent.atomic

If you are doing a multiple operations on x, that requires setting it to a new value at the end, it is possible to do this in a thread safe manner with no locking what so ever, and have it be thread safe, using compare and set. Example:

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.

Unstep answered 23/11, 2009 at 11:15 Comment(3)
Thanks for good reply. Yeah I looked there is no AtomicDouble and so I ended up with locking a dummy object and do my double assignment. As per you volatile is fine. But is this true in case of double?Mechanist
Well the fact that AtomicLong defines its value as volatile and the definition of AtomicLong.set is simply "value = newValue" I would take that as good evidence that 64 bit volatile variables have atomic assignments as of java 1.6.Unstep
That's a well-written example with unusual intent: it spins until it's finally able to overwrite value x. More typical would be to compute an updated value, try to store it, and, upon failure, to give up, assuming that some other thread got in there and advanced the situation first. The contract in your example is that every competing thread will advance the value once, doing whatever it takes in the face of contention.Knop
L
2

KDSRathore, you can use some explicit locks, or make some dummy Object object = new Object() , on which you synchronize in setter/getter of that double

Lutestring answered 22/11, 2009 at 17:6 Comment(2)
It is more recommended to use the existing atomic wrappers for the primitives than implementing them yourself.Conformity
Where does it say that existing atomic wrappers are preferred to a dedicated lock? A dedicated lock can be better as the scope of the lock is limited.Ordain
I
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."

Intervalometer answered 8/12, 2017 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.