Synchronizing on the return value (class object) of the Object.getClass()
method, rather than a class literal can lead to unexpected behavior. Whenever the implementing class is subclassed, the subclass locks on the subclass's type, which is a completely different Class
object (subclass's type).
Wiki Markup |
---|
Section 4.3.2 "The Class Object" of the Java Language specification \[[JLS 05|AA. Java References#JLS 05]\] describes how method synchronization works: |
...
This noncompliant code example synchronizes on the class object returned by getClass()
.
Code Block | ||
---|---|---|
| ||
class Base { public void doSomething() { synchronized(getClass()) { // ... } } } class Derived extends Base { public Base getBase(); { // ... } public void doSomethingElse() { Base obj = getBase(); obj.doSomething(); } } |
The actual Class
object that gets locked when Base.doSomething()
gets invoked depends on the return value of getBase()
. If getBase()
returns a Derived
, then doSomething()
locks on Derived.class
, not Base.class
.
Compliant Solution (class name qualification)
Explicitly define the name of the class through name qualification (superclass Base
in this compliant solution) in the synchronized block.
Code Block | ||
---|---|---|
| ||
class Base { public void doSomething() { synchronized(SuperclassNameBase.class) { // ... } } } |
This code example always synchronizes on the Base.class
object, even if it is called from a Derived
object.
The class object that is being used for synchronization should not be accessible to untrusted code. If the class is package-private, callers from other packages may not access the class object, ensuring its trustworthiness as an intrinsic lock object. For more information, see CON04-J. Synchronize using an internal private final lock object.
...
This compliant solution uses the Class.forName()
method to synchronize on the superclass Base
class's Class
object.
Code Block | ||
---|---|---|
| ||
class Base { public void doSomething() { synchronized(Class.forName("SuperclassNameBase")) { // ... } } } |
The class object that is being used for synchronization should also not be accessible to untrusted code, see CON04-J. Synchronize using an internal private final lock object for more information. Furthermore, care must be taken to ensure that untrusted inputs are not accepted as arguments while loading classes using Class.forname()
. (See SEC05-J. Do not expose standard APIs that use the immediate caller's class loader instance to untrusted code for more information.)
...