我遇到了tomcat抛出的问题OutOfMemoryError
:
SEVERE: Servlet.service() for servlet DataPortServlet threw exception
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.addIfUnderMaximumPoolSize(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
...
我要做的是:当在servlet中接收到数据时,将接收到的数据通过HttpClient
相关代码发送到另一台服务器:
小服务程序:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
...
byte[] data = getDataFromRequest(request); // pseudo code, get data
CallableLogSender sender = new CallableLogSender(data);
pool.submit(sender); // here the pool is the one instantiated at the start of application, singleton
...
}
类实现Callable
接口:
public class CallableLogSender implements Callable<Integer> {
private byte[] content;
public CallableLogSender(byte[] content) {
this.content = content;
}
@Override
public Integer call() {
try {
String uri = getRemoteServerUri(); // pseudo code, get uri here
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/x-www-form-urlencoded");
request.setEntity(new ByteArrayEntity(content));
HttpClient httpClient = getHttpClient(); // pseudo code, get cached http client, it is a singleton instance
HttpResponse response = httpClient.execute(request);
statusCode = response.getStatusLine().getStatusCode();
EntityUtils.consume(response.getEntity());
} catch(Exception e) {
// log error here...
} finally {
request.releaseConnection();
}
return statusCode;
}
}
如代码所示,submit
每次有客户端连接时,我对线程池进行了一个任务,然后我使用jProfiler监控tomcat,它显示池中的线程数一直在增加!并且所有线程都处于waiting
状态,所以当线程数超过阈值时,OutOfMemoryError
就会发生。
在我看来,线程应该重用,线程数应该稳定,至少不会一直增加,不知道是不是因为waiting
状态让池认为线程都“忙”了,所以new thread需要创建。
那么关于如何使池重用线程而不总是创建新线程的任何建议?
提前致谢, 开尔文
编辑:最后我找到根本原因是因为http请求响应时间太长,所以如果任务是突发提交的,线程数会一直在增加,因为一个任务完成时间太长。