Hi Felix,
I have just committed a fix so that the async client uses  
ExecutorService rather than creating a new thread. By default the  
implement returned from Executors.newCachedThreadPool() is utilized  
but you can set your own implementation on the Client.
Paul.
On Aug 25, 2010, at 10:54 AM, Paul Sandoz wrote:
> Hi Felix,
>
> After some email exchange with one of your colleagues i understand  
> the problem now, i overlooked the "asynchronous" in your first email.
>
> Because we create a new thread for every client request (the  
> illusion of async) a new parser instance will be created every time,  
> hence the contention you point out.
>
> I think the right solution here is to use a proper underlying async  
> API, which obviously requires a little more work (and we may be  
> required to break some APIs, also filtering needs to be changed, i  
> wrote a proposal on this list a while ago on how to do that).
>
> Another simpler interim solution is consider using of a thread pool.  
> I think the async handler impl:
>
>    public Future<ClientResponse> handle(final ClientRequest request,  
> final FutureListener<ClientResponse> l) {
>        Callable c = new Callable() {
>            public Object call() throws Exception {
>                return getHeadHandler().handle(request);
>            }
>        };
>        FutureTask<ClientResponse> ft = new  
> FutureTask<ClientResponse>(c) {
>            @Override
>            protected void done() {
>                try {
>                    l.onComplete(this);
>                } catch (Throwable t) {
>                    LOGGER.log(Level.SEVERE,
>                            "Throwable caught on call to  
> ClientResponseListener.onComplete",
>                            t);
>                }
>            }
>        };
>
>        new Thread(ft).start();
>        return ft;
>    }
>
> could use a pool and the done methods of "ft" could return the  
> thread to the pool. It does mean that the number of requests could  
> be limited waiting for a thread to become available (but there would  
> i suspect be some blocking lower down in the HttpURLConnection at  
> some point when enough threads are utilized as they will contend for  
> IO/CPU resources).
>
> Paul.
>
>
> On Aug 19, 2010, at 6:29 PM, Paul Sandoz wrote:
>
>> 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)
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>