I am interested in keeping my code running as fast as possible. Is there a cost associated with making my methods synchronized, and if so, how significant a cost?
There is a time penalty associated with executing synchronized
methods and blocks. The value of this penalty varies depending on the
virtual machine, the underlying operating system, the thread
implementation, and other factors. When you execute a synchronized
method or block, the JVM checks if the calling thread owns the monitor
associated with synchronized code. If so, the JVM increments a
counter associated with the monitor to account for recursive lock
acquisition and execution continues normally until the end of the
synchronized code is reached, whereupon the JVM decrements the lock
counter. If the counter equals zero, the JVM releases the thread's
ownership of the monitor. If the calling thread did not already own
the monitor, the JVM checks to see if any other thread already owns
the monitor. If so, the calling thread is blocked until the monitor
is released and another attempt to acquire it can be made. If not,
the JVM assigns ownership of the monitor to the thread and increments
the lock counter.
All of the aforementioned tasks consume CPU cycles that would not
normally be executed in unsynchronized code. A JVM or JIT, such as
HotSpot, can perform various optimizations to reduce the cost of these
tasks. But there will always be a cost. The only way to assess the
impact on the performance of your code is to time the code in your
projected production environment. You can also take steps to make
sure you are not unnecessarily using synchronization. Blindly
synchronizing all the methods of a class is often not necessary. Two
methods may access completely different data structures and not
require mutual exclusion. In such a case, you would eschew declaring
the methods as synchronized. Instead, you would create separate lock
variables for use in synchronized blocks in each method.
It is possible to squeeze better performance out of threaded programs by
only synchronizing those code blocks that require protection.
Unfortunately, performance is also very sensitive to the JVM.
Traditionally, the high-overhead implementations of synchronization in
JVMs has discouraged fine-grained synchronization. This encouraged
the synchronization of large code blocks. In an optimized runtime
like HotSpot, fine-grained synchronization is more efficient, causing
old code with coarse-grained locks to unnecessarily block threads for
long periods of time. In the end, the rule with multithreaded code is
that you've got to measure your actual performance against your
requirements and tweak accordingly.