views:

1884

answers:

4

Hi all,

All the while, I am using HttpClient in multithreaded environment. For every threads, when they initiate a connection, they will create a complete new HttpClient instance.

Recently, I discover, by using this approach, it can cause the user is having too many port being opened, and most of the connections are in TIME_WAIT state.

http://www.opensubscriber.com/message/[email protected]/86045.html

Hence, instead of per thread doing :

HttpClient c = new HttpClient();
try {
    c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

We plan to have :

[METHOD A]

// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());

try {
    global_c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

In normal situation, global_c will be accessed by 50++ threads concurrently. I was wondering, whether this will occur any performance issue? Is MultiThreadedHttpConnectionManager using lock-free mechanism to implement its thread safe policy?

It is possible if 10 threads are using global_c, will the other 40 threads being locked?

Or will it better if in every threads, I create a instance for every HttpClient, but release the connection manager explicitly.

[METHOD B]

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
HttpClient c = new HttpClient(connman);
try {
      c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
    connman.shutdown();
}

Is connman.shutdown() suffer performance issues?

May I know which method (A or B) is better, for application using 50++ threads?

+1  A: 

My reading of the docs is that HttpConnection itself is not treated as thread safe, and hence MultiThreadedHttpConnectionManager provides a reusable pool of HttpConnections, you have a single MultiThreadedHttpConnectionManager shared by all threads and initialised exactly once. So you need a couple of small refinements to option A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

Then each thread should be using the sequence for every request, getting a conection from the pool and putting it back on completion of its work - using a finally block may be good. You should also code for the possibility that the pool has no available connections and process the timeout exception.

HttpConnection connection = null
try {
    connection = connman.getConnectionWithTimeout(
                        HostConfiguration hostConfiguration, long timeout) 
    // work
} catch (/*etc*/) {/*etc*/} finally{
    if ( connection != null )
        connman.releaseConnection(connection);
}

As you are using a pool of connections you won't actually be closing the connections and so this should not hit the TIME_WAIT problem. This approach does assuume that each thread doesn't hang on to the connection for long. Note that conman itself is left open.

djna
Didn't actual answer to my question, on which method (A or B) is better.
Yan Cheng CHEOK
The answer was that neither is correct. I'll spell it out.
djna
+1  A: 

Method A is recommenced by httpclient developer community.

Please refer http://www.mail-archive.com/[email protected]/msg02455.html for more details.

Yan Cheng CHEOK
A: 

I think you will want to use ThreadSafeClientConnManager.

You can see how it works here: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

Or in the AndroidHttpClient which uses it internally.

Thomas Ahle
Opps. No plan to migrate from HttpClient 3.x to 4.x, as 3.x had been running flawless in my application for nearly ~2 years :)
Yan Cheng CHEOK
Sure, just if somebody else came here Googling for an answer :)
Thomas Ahle
+2  A: 

Definitely Method A because its pooled and thread safe.

If you are using httpclient 4.x, the connection manager is called ThreadSafeClientConnManager. See this link for further details (scroll down to "Pooling connection manager"). For example:

    HttpParams params = new BasicHttpParams();
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
    HttpClient client = new DefaultHttpClient(cm, params);
numes