java - 是否同步 PoolingClientConnectionManager

标签 java android http singleton synchronize

在我的应用程序中,有多个 IntentService 根据用户与应用程序的交互以随机间隔与 Tomcat 服务器连接/通信。

我正在为 Http 使用以下 Singleton

public class CustomHttpClient { 
    private static HttpClient customHttpClient; 
    /** A private Constructor prevents instantiation */ 
    private CustomHttpClient() { 
    } 

    public static synchronized HttpClient getHttpClient() { 
        if (customHttpClient == null) { 
            HttpParams params = new BasicHttpParams(); 
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
            HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); 
            HttpProtocolParams.setUseExpectContinue(params, true); 
            HttpProtocolParams.setUserAgent(params,"Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83)" +
                    " AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"); 
            ConnManagerParams.setTimeout(params, 1000); 
            HttpConnectionParams.setConnectionTimeout(params, 5000); 
            HttpConnectionParams.setSoTimeout(params, 10000); 
            SchemeRegistry schReg = new SchemeRegistry(); 
            schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
            schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 
            ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg); 
            customHttpClient = new DefaultHttpClient(conMgr, params); 
        } 
        return customHttpClient; 
    } 
    public Object clone() throws CloneNotSupportedException { 
        throw new CloneNotSupportedException(); 
    } 
}

除了当两个 IntentService 同时尝试 Http 或者当一个连接正在进行并且另一个连接已建立时它会给出 connectTimeOut 之外,该类工作正常。 p>

代码中的一个明显改进是用 PoolingClientConnectionManager 替换弃用的 ThreadSafeClientConnManager

我应该在此处同步 -> public static synchronized HttpClient getHttpClient()

导致 connectTimeOut 的单例中有什么错误?

最佳答案

Synchronize the PoolingClientConnectionManager or not?

是也不是。如果您希望 getHttpClient() 成为单例(IMO 是个好主意),您必须使其线程安全。这需要 synchronized。如果没有 synchronized,两个线程可以同时进入 if block (因为 customHttpClient == null 对两个线程都是 true)并创建两个实例。

但是有更好的(和更快的)方法不用 synchronized 来创建线程安全的单例。我喜欢Singleton Holder例如方法。

但是无论您在这里使用的是什么单例,都不应该出现连接超时。如果您为每个线程使用新的 HttpClient 实例,它也应该可以工作。


如果发生连接超时,则您的线程之一无法在您使用 HttpConnectionParams.setConnectionTimeout(params, 5000); = 5 秒设置的时间限制内连接到服务器。

这可能有几个原因。例如,如果您的连接缓慢且不稳定,则可能需要更长的时间,因为您的连接可能会中断几秒钟。或者,如果您的服务器由于配置(例如每个 IP 的连接限制)或因为硬件无法处理更多连接而无法处理更多连接,您也会看到此问题。基本上任何阻止 HttpClient 向服务器发送数据包或从服务器接收数据包的事情都会触发该问题。意味着您的问题要么在设备上,要么在网络上,要么在服务器上。

我不知道您的网络设置,但您可以尝试增加超时时间,看看是否有任何效果。 AndroidHttpClient例如将这些超时设置为 60 秒。如果您使用的是 WiFi 且连接稳定,那么这远远超过要求,但在连接非常弱时也很好。

您还可以检查 AndroidHttpClient 应用的其他设置是否有帮助。

下面AndroidHttpClient的设置

// Default connection and socket timeout of 60 seconds.  Tweak to taste.
private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;

// ---------------------------------------------------------------------- //
HttpParams params = new BasicHttpParams();

// Turn off stale checking.  Our connections break all the time anyway,
// and it's not worth it to pay the penalty of checking every time.
HttpConnectionParams.setStaleCheckingEnabled(params, false);

HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
HttpConnectionParams.setSocketBufferSize(params, 8192);

// Don't handle redirects -- return them to the caller.  Our code
// often wants to re-POST after a redirect, which we must do ourselves.
HttpClientParams.setRedirecting(params, false);

// Use a session cache for SSL sockets
SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);

// Set the specified user agent and register standard protocols.
HttpProtocolParams.setUserAgent(params, userAgent);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http",
        PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
        SSLCertificateSocketFactory.getHttpSocketFactory(
        SOCKET_OPERATION_TIMEOUT, sessionCache), 443));

ClientConnectionManager manager =
        new ThreadSafeClientConnManager(params, schemeRegistry);

return new DefaultHttpClient(manager, params);

要确定您的问题出在哪里,您可以查看您的服务器连接日志并检查设备是否尝试启动连接,如果是,是否存在连接未建立的原因。如果超时时您没有看到任何连接尝试,则很可能是设备或网络问题。

如果您可以访问设备所连接的网络 (=WiFi),您可以使用例如Wireshark由于连接尝试超时的原因。您可以在那里看到设备是否发送连接请求。

最后但同样重要的是,它可能是由您的某些代码引起的。如果您找不到其他解决方案,请尝试使用 HttpURLConnection 实现它,看看是否有帮助。

关于java - 是否同步 PoolingClientConnectionManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12030331/

相关文章:

javascript - 当调用来自 iFrame 时,如何获取主机站点的 Http_Referrer?

java - 如何从单独的文件夹编译和运行项目?

java - 使用java将下载保存到浏览器下载而不是系统下载

android - 检测是否在 Android 上启用了 "Large Text"辅助功能选项

android - 为了节省内存,使用哪个 Intent 对象是更好的选择

java - 如何通过 Java HTTP 服务器发送图像

web-services - 什么是 REST API 错误处理最佳实践?

java - 我们如何在键不重复的列表中添加 Elasticsearch 结果(searchResponse)键和值

java - 关闭应用程序后服务未运行

javascript - 当用户从列表中选择时如何显示内容详细信息?