Avoid synchronized at method level

Viewed 558

PMD (source code analyzer) recommends to avoid synchronized at method level. It is actually obvious as when you call synchronized on method you are calling synchronized on this and that can lead to potential issues.

But PMD in this rule suggests the following example: Synchronized on method rule

public class Foo {
  // Try to avoid this:
  synchronized void foo() {
  }
  // Prefer this: <----- Why? Isn't it the same on byte-code level
  void bar() {
    synchronized(this) {
    }
  }
}

Is it a bug in a specification of PMD (in the example) or synchronized on method works differently from synchronized(this)?

3 Answers

Yes, it is technically the same. This is about code style, not correctness.

The link you posted explains the reason quite well:

Method-level synchronization can cause problems when new code is added to the method. Block-level synchronization helps to ensure that only the code that needs synchronization gets it.

An additional rule in SB_CONTRIB discourages use of this in synchronized since the class object can be used by other threads to lock on as well.

http://fb-contrib.sourceforge.net/bugdescriptions.html

NOS_NON_OWNED_SYNCHRONIZATION This method uses a synchronize block where the object that is being synchronized on, is not owned by this current instance. This means that other instances may use this same object for synchronization for their own purposes, causing synchronization confusion. It is always cleaner and safer to only synchronize on private fields of this class. Note that 'this' is not owned by the current instance, but is owned by whomever assigns it to a field of its class. Synchronizing on 'this' is also not a good idea.

In conjunction with this Spotbugs rule, it is more than good style to not synchronize the entire method body.

The “correct” versions are bugs in the PMD documentation, at the very least.

The point of the rule is to indicate that placing an entire method body in a synchronization block is probably unnecessary; in most cases, only the code accessing a multi-threaded resource needs to be synchronized. So the examples should show, or imply, that there is some code before and/or after the synchronized block.

Related