In a class that has many instances, is it better to use synchronization, or an atomic variable for fields?
I am writing a class of which will be created quite a few instances. Multiple threads will be using these instances, so the getters and setters of the fields of the class have to be concurrent. The fields are mainly floats. Thing is, I don't know what is more resource-hungry开发者_Python百科; using a synchronized section, or make the variable something like an AtomicInteger?
You should favor atomic primitives when it is possible to do so. On many architectures, atomic primitives can perform a bit better because the instructions to update them can be executed entirely in user space; I think that synchronized
blocks and Lock
s generally need some support from the operating system kernel to work.
Note my caveat: "when it is possible to do so". You can't use atomic primitives if your classes have operations that need to atomically update more than one field at a time. For example, if a class has to modify a collection and update a counter (for example), that can't be accomplished using atomic primitives alone, so you'd have to use synchronized
or some Lock
.
The question already has an accepted answer, but as I'm not allowed to write comments yet here we go. My answer is that it depends. If this is critical, measure. The JVM is quite good at optimizing synchronized accesses when there is no (or little) contention, making it much cheaper than if a real kernel mutex had to be used every time. Atomics basically use spin-locks, meaning that they will try to make an atomic change and if they fail they will try again and again until they succeed. This can eat quite a bit of CPU is the resource is heavily contended from many threads.
With low contention atomics may well be the way to go, but in order to be sure try both and measure for your intended application.
I would probably start out with synchronized methods in order to keep the code simple; then measure and make the change to atomics if it makes a difference.
It is very important to construct the instances properly before they have been used by multiple threads. Otherwise those threads will get incomplete or wrong data from those partially constructed instances. My personal preference would be to use synchronized block. Or you can also follow the "Lazy initialization holder class idiom" outlined by Brain Goetz in his book "Java concurrency in Practice":
@ThreadSafe
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
}
public static Resource getResource() {
return ResourceHolder.resource;
}
}
Here the JVM defers initializing the ResourceHolder class until it is actually used. Moreover Resource is initialized with a static initializer, no additional synchronization is needed.
Note: Statically initialized objects require no explicit synchronization either during construction or when being referenced. But if the object is mutable, synchronization is still required by both readers and writers to make subsequent modifications visible and also to avoid data corruption.
精彩评论