我有 1000 个专用 Java 线程,每个线程每秒轮询一个相应的 url。
public class Poller {
public static Node poll(Node node) {
GetMethod method = null;
try {
HttpClient client = new HttpClient(new SimpleHttpConnectionManager(true));
......
} catch (IOException ex) {
ex.printStackTrace();
} finally {
method.releaseConnection();
}
}
}
线程每秒运行一次:
for (int i=0; i <1000; i++) {
MyThread thread = threads.get(i) // threads is a static field
if(thread.isAlive()) {
// If the previous thread is still running, let it run.
} else {
thread.start();
}
}
问题是,如果我每隔一秒运行一次作业,我就会得到如下随机异常:
java.net.BindException: Address already in use
INFO httpclient.HttpMethodDirector: I/O exception (java.net.BindException) caught when processing request: Address already in use
INFO httpclient.HttpMethodDirector: Retrying request
但如果我每 2 秒或更长时间运行一次作业,一切都会运行良好。
我什至尝试使用 shutdown() 关闭 SimpleHttpConnectionManager() 的实例,但没有任何效果。
如果我执行 netstat,我会看到数以千计的 TCP 连接处于 TIME_WAIT 状态,这意味着它们已关闭并正在清理。
因此,为了限制连接数,我尝试使用单个 HttpClient 实例并像这样使用它:
public class MyHttpClientFactory {
private static MyHttpClientFactory instance = new HttpClientFactory();
private MultiThreadedHttpConnectionManager connectionManager;
private HttpClient client;
private HttpClientFactory() {
init();
}
public static HttpClientFactory getInstance() {
return instance;
}
public void init() {
connectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams managerParams = new HttpConnectionManagerParams();
managerParams.setMaxTotalConnections(1000);
connectionManager.setParams(managerParams);
client = new HttpClient(connectionManager);
}
public HttpClient getHttpClient() {
if (client != null) {
return client;
} else {
init();
return client;
}
}
}
然而,运行 2 小时后,它开始抛出“打开的文件太多”,最终什么也做不了。
ERROR java.net.SocketException: Too many open files
INFO httpclient.HttpMethodDirector: I/O exception (java.net.SocketException) caught when processing request: Too many open files
INFO httpclient.HttpMethodDirector: Retrying request
我应该能够增加允许的连接数并使其工作,但我只会延长邪恶。知道在上述情况下使用 HttpClient 的最佳做法是什么吗?
顺便说一句,我还在 HttpClient3.1 上。