users@jersey.java.net

Re: [Jersey] SAXParserContextProvider is a contention point

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Thu, 19 Aug 2010 18:29:06 +0200

Hi Felix,

The SAXParserContextProvider that extends
ThreadLocalSingletonContextProvider only creates a new instance of
SAXParserFactory per-thread (i.e. when a get is called on the thread
local and the value has not been set), it will not be creating a new
instance of SAXParserFactory every time one is created, so i would
expect any contention to be limited to an initialization period.

See:

   http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html#initialValue%28%29

Now that i think about it i am wondering why it is like this:

     protected ThreadLocalSingletonContextProvider(Class<T> t) {
         this.t = t;
         this.rf = new ThreadLocal<T>() {
             @Override
             protected synchronized T initialValue() {
                 return getInstance();
             }
         };
     }

and the synchronized is used. I think it was because i was not sure
what would happen if two threads were executing the following at the
same time:

   SAXParserFactory f = SAXParserFactory.newInstance();


And that is the general why we keep instances of SAXParserFactory per-
thread: we cannot guarantee that those implementations are thread safe
when utilized to obtain SAXParser instances. The spec and JavaDoc are
vague on the topic.

You can override by registering your own InjectableProvider
implementation that supports the SAXParserFactory type and registering
that implementation as a provider (annotate with @Provider to identify
and then register explicitly or via scanning).

Paul.


On Aug 19, 2010, at 5:06 PM, felix-etienne.trepanier_at_nokia.com wrote:

> Hi,
>
> I’ve been using the jersey default client (new Client()) using the
> asynchronous API on several thread simultaneously and noticed a
> contention point (see stacktrace bellow). The XMLRootElementProvider
> get a SAXParserContextProvider and used it to read the XML stream.
> The implementation of the SAXParserContextProvider is based on the
> ThreadLocalSingletonContextProvider which synchronizes the
> getInitialValue() but the implementation of SAXParserContextProvider
> recreates a new SAXParserFactory every time and this seems to be a
> costly operation. This causes contention.
>
> I’m trying to figure out how to inject another implementation of the
> SAXParserContextProvider that would not synchronize the creation of
> the SAXParserFactory. Pointers would be helpful.
>
> Thanks,
>
> Felix
> …
> at
> java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:1168)
> at javax.xml.parsers.SecuritySupport
> $4.run(SecuritySupport.java:96)
> at java.security.AccessController.doPrivileged(Native Method)
> at
> javax
> .xml
> .parsers.SecuritySupport.getResourceAsStream(SecuritySupport.java:89)
> at
> javax
> .xml.parsers.FactoryFinder.findJarServiceProvider(FactoryFinder.java:
> 250)
> at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:
> 223)
> at
> javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:
> 128)
> at
> com
> .sun
> .jersey
> .core
> .impl
> .provider
> .xml
> .SAXParserContextProvider.getInstance(SAXParserContextProvider.java:
> 65)
> at
> com
> .sun
> .jersey
> .core
> .impl
> .provider
> .xml
> .SAXParserContextProvider.getInstance(SAXParserContextProvider.java:
> 51)
> at
> com
> .sun
> .jersey.core.impl.provider.xml.ThreadLocalSingletonContextProvider
> $1.initialValue(ThreadLocalSingletonContextProvider.java:61)
> - locked <0x00002aaab578ecd8> (a
> com
> .sun
> .jersey.core.impl.provider.xml.ThreadLocalSingletonContextProvider$1)
> at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:141)
> at java.lang.ThreadLocal.get(ThreadLocal.java:131)
> at
> com
> .sun
> .jersey.core.impl.provider.xml.ThreadLocalSingletonContextProvider
> $2.getValue(ThreadLocalSingletonContextProvider.java:74)
> at
> com
> .sun
> .jersey
> .core
> .impl
> .provider
> .entity.XMLRootElementProvider.readFrom(XMLRootElementProvider.java:
> 110)
> at
> com
> .sun
> .jersey
> .core
> .provider
> .jaxb
> .AbstractRootElementProvider
> .readFrom(AbstractRootElementProvider.java:106)
> at
> com
> .sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:
> 549)
> at
> com
> .sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:
> 502)
> at com.sun.jersey.api.client.AsyncWebResource
> $3.get(AsyncWebResource.java:706)
> at
> com
> .sun
> .jersey
> .client
> .impl
> .async
> .FutureClientResponseListener
> .onComplete(FutureClientResponseListener.java:103)
> at com.sun.jersey.api.client.AsyncWebResource
> $6.done(AsyncWebResource.java:749)
> at java.util.concurrent.FutureTask
> $Sync.innerSet(FutureTask.java:251)
> at java.util.concurrent.FutureTask
> $Sync.innerRun(FutureTask.java:303)
> at java.util.concurrent.FutureTask.run(FutureTask.java:138)
> at java.lang.Thread.run(Thread.java:619)
>
> "Thread-42745" daemon prio=10 tid=0x00002aaafa221000 nid=0x9ca
> waiting for monitor entry [0x00002aab74f8a000..0x00002aab74f8ab10]
> java.lang.Thread.State: BLOCKED (on object monitor)
> at
> com
> .sun
> .jersey.core.impl.provider.xml.ThreadLocalSingletonContextProvider
> $1.initialValue(ThreadLocalSingletonContextProvider.java:61)
> - waiting to lock <0x00002aaab578ecd8> (a
> com
> .sun
> .jersey.core.impl.provider.xml.ThreadLocalSingletonContextProvider$1)
> at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:141)
> at java.lang.ThreadLocal.get(ThreadLocal.java:131)
> at
> com
> .sun
> .jersey.core.impl.provider.xml.ThreadLocalSingletonContextProvider
> $2.getValue(ThreadLocalSingletonContextProvider.java:74)
> at
> com
> .sun
> .jersey
> .core
> .impl
> .provider
> .entity.XMLRootElementProvider.readFrom(XMLRootElementProvider.java:
> 110)
> at
> com
> .sun
> .jersey
> .core
> .provider
> .jaxb
> .AbstractRootElementProvider
> .readFrom(AbstractRootElementProvider.java:106)
> at
> com
> .sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:
> 549)
> at
> com
> .sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:
> 502)
> at com.sun.jersey.api.client.AsyncWebResource
> $3.get(AsyncWebResource.java:706)
> at
> com
> .sun
> .jersey
> .client
> .impl
> .async
> .FutureClientResponseListener
> .onComplete(FutureClientResponseListener.java:103)
> at com.sun.jersey.api.client.AsyncWebResource
> $6.done(AsyncWebResource.java:749)
> at java.util.concurrent.FutureTask
> $Sync.innerSet(FutureTask.java:251)
> at java.util.concurrent.FutureTask
> $Sync.innerRun(FutureTask.java:303)
> at java.util.concurrent.FutureTask.run(FutureTask.java:138)
> at java.lang.Thread.run(Thread.java:619)
>