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)
...
私がやりたいことは、サーブレットでデータを受信すると、受信したデータを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
私の意見では、スレッドを再利用する必要があり、スレッド番号は安定している必要があります。少なくとも常に増加するとは限りません。状態がプールにスレッドがすべて「ビジー」であると思わせるためかどうかはわかりません。したがって、新しいスレッド作成する必要があります。
では、プールでスレッドを再利用し、常に新しいスレッドを作成するのではなくする方法について何か提案はありますか?
よろしくお願いします、ケルビン
編集: 最後に、根本的な原因は、http 要求の応答に時間がかかりすぎるためであることがわかりました。そのため、タスクがバーストで送信されると、1 つのタスクが完了するのに時間がかかりすぎるため、スレッド数が常に増加します。