United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6963811 Deadlock-prone locking changes in Introspector
JDK-6963811 : Deadlock-prone locking changes in Introspector

Details
Type:
Bug
Submit Date:
2010-06-24
Status:
Resolved
Updated Date:
2013-04-20
Project Name:
JDK
Resolved Date:
2010-07-21
Component:
client-libs
OS:
generic
Sub-Component:
java.beans
CPU:
generic
Priority:
P2
Resolution:
Fixed
Affected Versions:
6u21
Fixed Versions:

Related Reports
Backport:
Backport:
Backport:
Relates:
Relates:

Sub Tasks

Description
Locking model of Introspector changed by fix of
bug 5102804. The code

(new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();

is called under BEANINFO_CACHE lock by now, see getBeanInfo(Class) method.
This code can invoke 3rd-party code through findExplicitBeanInfo().
It is deadlock-prone to call 3rd-party code under some lock
and it should be avoided where it is possible.

See the following test-case. It shows how easily the mentioned
changes can result in a deadlock.

-------------------------------------------------

package problemofintrospector;

import java.awt.Point;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.SimpleBeanInfo;

public class TestCase {

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    // Get some BeanInfo in one thread
                    Introspector.getBeanInfo(CustomizedPoint.class, Object.class);
                } catch (IntrospectionException iex) {}
            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    // Get some BeanInfo in another thread
                    Introspector.getBeanInfo(Point.class);
                } catch (IntrospectionException iex) {}
            }
        });
        t1.start();
        Thread.sleep(500); // increase the chance of the deadlock
        t2.start();
    }

    public static class CustomizedPoint extends Point {
    }

    public static class CustomizedPointBeanInfo extends SimpleBeanInfo {
        private BeanInfo superInfo;

        public CustomizedPointBeanInfo() {
            try {
                Thread.sleep(1000); // increase the chance of the deadlock
                superInfo = Introspector.getBeanInfo(Point.class);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        // Real-life BeanInfo would contain some additional
        // methods overriden and some work delegated to superInfo
        // (the corresponding code is skipped because it is not
        // necessary to reproduce the deadlock).

    }

}

-------------------------------------------------

Note that the test-case doesn't run into deadlock on older JDK builds
(pre JDK 6 update 21 build 02), i.e., it is a regression. Also note
that this test-case is not an artifical one. It is based on a deadlock
that one of our users faces regularly while using NetBeans GUI Builder.

                                    

Comments
SUGGESTED FIX

The fix of issue 5102804 uses BEANINFO_CACHE lock to synchronize
beanInfoCache collection. You can either make this collection
synchronized using Collections.synchronizedMap (and strip
the synchronization in getBeanInfo(Class)) or leave the collection
as it is and (at least) move invocation of 

(new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();

outside BEANINFO_CACHE lock, i.e., replace

synchronized (BEANINFO_CACHE) {
    ...
    BeanInfo beanInfo = beanInfoCache.get(beanClass);
    if (beanInfo == null) {
        beanInfo = (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
        beanInfoCache.put(beanClass, beanInfo);
    }
}

by

synchronized (BEANINFO_CACHE) {
    ...
    BeanInfo beanInfo = beanInfoCache.get(beanClass);
}
if (beanInfo == null) {
    beanInfo = (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
    synchronized (BEANINFO_CACHE) {
        beanInfoCache.put(beanClass, beanInfo);
    }
}
                                     
2010-06-24
WORK AROUND

Use Introspector on a single thread.
                                     
2010-06-24
EVALUATION

It was introduced by the fix of the 5102804 CR or the 6380849 CR.  The reason is that the BeanInfo finder uses own mutex.  We should either use the Introspector's mutex for the finder or synchronize mutable fields only.
                                     
2010-06-24



Hardware and Software, Engineered to Work Together