When should the methods of my class be synchronized?

I was thinking of creating a class (e.g. String, StringBuffer, etc.). This can be used in both single-threaded and multi-threaded environments. I donโ€™t know which environment the developer could use. Anticipating the worst case scenario, I can synchronize.

But, 1. Synchronization leads to a performance hit. 2. Without synchronization, it is not thread safe.

So, I have two options.

  • Leave the class unsynchronized - but the developer using this class should synchronize it when necessary.
  • Have all methods synchronized - and take off productivity.

I have seen that many (if not all, for example, ArrayList over Vector) classes in Java have evolved to use the first approach. What are some of the things I need to consider before deciding on these two options for my class?

Or, to put it another way, should I use "public synchronized void bar ()" over "public void bar ()" only when I know for sure that the panel can be used in a multi-threaded environment and should not start at the same time?

EDIT So, I obviously misused the word "utility class" in the title. Thanks, John Skeet, for this. I removed the world "utility" from the header.

To give an example, I was thinking of a class like Counter. An example is a counter. There are other ways to implement Counter. But this question is about synchronization. The Counter object keeps track of how many times something has been done. But it can be used in single-threaded or multi-threaded environments. So, how should I handle the synchronization problem in Counter.

+7
source share
5 answers

What I consider to be a utility class โ€” usually a bag with undefined public static methods โ€” rarely requires any kind of synchronization. If a class does not support some kind of mutable state, you are usually absolutely fine.

Of course, if you take parameters that themselves are shared between threads and contain mutable state, you may need synchronization - but this should be for the calling user, usually.

If you mean something else in the "utility class", it would be nice to know what you mean. If it is a class without a mutable state (but possibly an immutable state set during construction), then it is usually perfectly divided between threads.

If it has a mutable state but is not explicitly associated with threads, I would usually not put any synchronization in this class, but document that it is not thread safe. Typically, callers need to synchronize multiple operations using multiple objects, so synchronizing the โ€œmethod at a timeโ€ usually does not help.

If this is a class that is related to threading (for example, something to control the producer / consumer queues), I would try to make it thread safe, but document what you mean by that. I would advise you not to synchronize the methods themselves, but instead to synchronize in a closed final field, which is used only for synchronization; this way, your class will contain the only code that can be synchronized on this object, which simplifies the discussion about your lock.

You will almost certainly not make these decisions based on performance. Correctness and simplicity in most cases are much more important than performance.

+10
source

As for your last question: you are not synchronizing a method if it can be called from multiple threads. You synchronize a method if it uses some state that can be accessed from multiple threads.

So, even if your bar() method is called from only one thread, if it accesses an instance variable that is read and modified, in other ways, by multiple threads, then the bar() method must be synchronized (or at least a block of code, which refers to a shared variable). Synchronization is a general condition.

EDIT:

Regarding your main problem: you can simply use the same strategy as the collection infrastructure: make your counter an interface and provide a standard, non-thread safe implementation. Also specify a utility class ( Counters ) containing a method that returns a synchronized proxy counter Counter: Counters.synchronizedCounter(Counter counter); .

So you have the best of both worlds. Note that an important point of this project is that the synchronized counter synchronizes on its own. This allows callers to add external synchronization in case two method calls on the counter must be made in an atomic way:

 Counter synchronizedCounter = Counters.synchronizedCounter(c); // call a and b atomically: synchronized (synchronizedCounter) { synchronizedCounter.a(); synchronizedCounter.b(); } 
+2
source

While synchronization performance has been improved, as well as other parts of the virtual machine. Therefore, synchronization is still noticeable overhead information.

In particular, synchronization actions prevent many optimization tricks. Even if the VM can perform evacuation analysis, the VM must still maintain reordering and add a memory barrier to match the Java memory model.

+1
source

These days, the "performance hit" from synchronization is remarkably small. You should only worry about this if you have evidence that synchronization is causing performance issues.

You may need to synchronize if your class has state through static fields, which are links by several methods. In this case, it would be preferable to have instance fields and use the singleton pattern, which more clearly tells other programmers what the class intends.

0
source

The performance degradation for single-threaded access to synchronized methods on modern JVMs is practically not noticeable.

But why not create a benchmark and see for yourself?

0
source

All Articles