Is there any difference between AtomicReference and Synchronized?
E.G.
public class Internet {
AtomicReference<String> address;
public String getAddress(){
return address.toString();
}
public void setAddress(String address) {
this.address.set(address);
}
}
And I pass the class to some threads that try to use the class at the same time, is it the same thing if I use this:
public class Internet {
String address;
public String getAddress(){
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
And then in the thread use synchronized
before access to the class?
There's nothing wrong with the other answers here if you can understand them, but they mostly seem to focus on details, nomenclature, and use-cases, while skipping over the big picture that "everybody" already knows.
Here's the big picture---the difference between an
AtomicFoobar
operation and asynchronized
block.An AtomicFoobar operation (e.g., atomicReference.compareAndSet(...)) either performs exactly one, very simple, thread-safe operation, or else it fails. Regardless of whether it succeeeds or fails, it will never make the thread wait.
A
synchronized
block, on the other hand is as complicated as you make it---there is no limit to how many statements are executed while the lock is locked. Asynchronized
block will never fail, but it may make the calling thread wait until the operation(s) can be safely performed.On most architectures, each AtomicFoobar methods is implemented as a Java native method (i.e., C code) that executes a single, specialized hardware instruction. Synchronized, on the other hand is most always implemented with operating system calls which, somewhere deep in the guts, probably make use of the same hardware instructions.
You didn't initialize the reference in the first example, it should probably be:
Where the access restriction is located is important. If you put the control within the object being accessed then it can have sole control of its invariants, which is much less fragile than relying on the threads to all synchronize properly, where one badly behaved accessing thread can corrupt the thing being accessed. So the first example is much better on that account.
If you change the second example so that the object has control over its own locking (so it is not relying on threads accessing it to do so safely), like this:
then it's a closer comparison, one relies on locking and the other on atomic references. The one using AtomicReference tries to avoid locking using machine-level atomic processing instructions. Which is faster may depend on your hardware and jvm and the processing load, typically the atomic approach should be faster. The synchronized approach is a more general purpose mechanism; with the synchronized block you can group together multiple assignments much more easily, where with atomic references it's much more involved.
As James says in his answer, with synchronization your threads are waiting for a lock; there is no timeout, and deadlock is possible. With the atomic reference the thread makes its change with no waiting on a shared lock.
The simplest and best-performing way to implement this would be to organize your code so that you can make the object immutable, so you would avoid all locking, busy-waiting, and cache updating:
In descending order of preference:
A
synchronized
method/block blocks all access to that method/block from other threads while one thread is performing the method.An
Atomic...
can be accessed by many threads at once - there are usually CAS access methods available for them to help with high-speed access.As such - they are completely different but they can sometimes be used to solve parallel accessibility issues.
These two classes use the two different methods to return a steadily increasing number such that the same number will never be delivered twice. The
AtomicInteger
version will run faster in a high-load environment. The one usingsynchronized
will work in Java 4 and older.