我遇到了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
将收到的数据发送到另一台服务器,相关代码:
的servlet:
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
状态使得池认为线程是所有“忙”,所以需要创建新的线程。
那么关于如何使池重用线程并且不总是创建新线程的任何建议?
先谢谢,凯尔文
编辑:最后我发现根本原因是因为http请求需要很长时间才能响应,所以如果以突发方式提交任务,则线程数将始终增加,因为一个任务需要很长时间才能完成。