Wiki Markup |
---|
Code that uses synchronization can sometimes be enigmatic and tricky to debug. Misuse of synchronization primitives is a common source of implementation errors. TheAn analysis of the JDK 1.6.0 source code unveiled at least 31 bugs that fell into this category. \[[Pugh 08|AA. Java References#Pugh 08]\] |
...
Wiki Markup |
---|
A {{String}} constant is interned in Java. According to the Java API \[[API 06|AA. Java References#API 06]\] Class {{String}} documentation: |
...
Consequently, a String
constant behaves like a global variable in the JVM. As demonstrated in this noncompliant code example, even if each instance of an object maintains its own field lock
, it points to a common String
constant in the JVM. Legitimate code that locks on the same String
constant will render renders all synchronization attempts inadequate. Likewise, hostile code from any other package can deliberately exploit this vulnerability.
Code Block | ||
---|---|---|
| ||
// thisThis bug was found in jetty-6.1.3 BoundedThreadPool private final String _lock = "one"; synchronized(_lock) { /* ... */ } |
...
Code Block |
---|
int lock = 0; Integer Lock = lock; // boxedBoxed primitive Lock will be shared |
...
Code Block | ||
---|---|---|
| ||
private Boolean initialized = Boolean.FALSE; synchronized(initialized) { if (!initialized) { // performPerform initialization initialized = Boolean.TRUE; } } |
...
Note that the instance of the raw object should not be changed from within the synchronized block. For example, creating and storing the reference of a new object into the lock
field is highly inadvisable. To prevent such modifications, declare the lock
field final
.
...
This does not mean that it is required to synchronize on the Class
object of the base class.
Compliant Solution
Explicitly define the name of the class (superclass in this example) in the synchronization block. This can be achieved in two ways. One way is to explicitly pass the superclass's instance.
...
Code Block | ||
---|---|---|
| ||
Map<Integer, String> m = Collections.synchronizedMap(new HashMap<Integer, String>()); Set<Integer> s = m.keySet(); synchronized(s) { // Incorrectly synchronizes on s for(Integer k : s) { //* doDo something */ } } |
Compliant Solution
This compliant solution correctly synchronizes on the Collection
object instead of the Collection
view.
Code Block | ||
---|---|---|
| ||
// ... synchronized(m) { // Synchronize on m, not s for(Integer k : s) { //* doDo something */ } } |
Noncompliant Code Example
...
Code Block | ||
---|---|---|
| ||
final Lock lock = new ReentrantLock(); synchronized(lock) { /* do something... */ } |
Compliant Solution
The proper mechanism to lock in this case is to explicitly use the lock()
and unlock()
methods provided by the ReentrantLock
class.
...