我正在运行多线程java应用程序,其中下面的方法将由多个线程(大约300个)并行执行。我只在线程数较多时看到此异常,但在线程数小于50时则看不到。 我在stackoverflow中阅读了一些帖子,代码看起来对所描述的帖子抱怨。任何帮助,将不胜感激。提前谢谢。
这是我的方法:
public static String invokeWebService(String request, String fwfmId, BatchVO batchVO){
String responseString = "";
//log the request string
Logger_trace.info("Service request for input "+ fwfmId +":: "+CommonUtil.removeCrLf(request));
try {
URL url = new URL(batchVO.getWebServiceUrl());
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-type", "text/xml; charset=utf-8");
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setConnectTimeout(Integer.parseInt(batchVO.getConnectionTimeOut()));
urlConnection.setReadTimeout(Integer.parseInt(batchVO.getReadTimeOut()));
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(request.getBytes());
outputStream.flush();
//get response form input stream and convert into string
InputStreamReader inputStreamReader = new InputStreamReader(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = bufferedReader.readLine()) != null) {
response.append(inputLine);
}
responseString = response.toString();
//close resources
bufferedReader.close();
inputStreamReader.close();
outputStream.close();
//log the response string
logger_trace.info("Service response for input "+ fwfmId +":: "+ CommonUtil.removeCrLf(responseString));
//Update Database columns
updateRecordInTable(request, responseString, fwfmId, batchVO.getDataSource(), batchVO.getBatchId());
} catch (SocketConnectException e) {
logger_trace.error("WebserviceHandler.invokeWebService : SocketConnectException block : "+fwfmId +" ", e);
updateRecordInTableWithTimeout(fwfmId, batchVO.getDataSource(), batchVO.getBatchId());
} catch (SocketTimeoutException e) {
logger_trace.error("WebserviceHandler.invokeWebService : SocketTimeoutException block : "+ fwfmId+" ", e);
updateRecordInTableWithTimeout(fwfmId, batchVO.getDataSource(), batchVO.getBatchId());
} catch (MalformedURLException e) {
logger_trace.error("WebserviceHandler.invokeWebService : MalformedURLException block : ", e);
} catch (IOException e) {
logger_trace.error("WebserviceHandler.invokeWebService : IOException block : ", e);
} catch(Exception e){
logger_trace.error("WebserviceHandler.invokeWebService : General Exception block : ", e);
}
return responseString;
}
例外:
[ERROR] 2017-10-31 03:18:54,435 [main] TRACE -
WebserviceHandler.invokeWebService : IOException block :
java.net.SocketException: Socket Closed
at java.net.AbstractPlainSocketImpl.setOption(AbstractPlainSocketImpl.java:212)
~[?:1.8.0_131]
at java.net.Socket.setTcpNoDelay(Socket.java:980) ~[?:1.8.0_131]
at weblogic.net.http.HttpClient.openServer(HttpClient.java:411)
~[wlfullclient.jar:12.2.2.0.0]
at weblogic.net.http.HttpClient.openServer(HttpClient.java:511)
~[wlfullclient.jar:12.2.2.0.0]
at weblogic.net.http.HttpClient.New(HttpClient.java:313) ~[wlfullclient.jar:12.2.2.0.0]
at weblogic.net.http.HttpURLConnection.getHttpClient(HttpURLConnection.java:314)
~[wlfullclient.jar:12.2.2.0.0]
at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:760)
~[wlfullclient.jar:12.2.2.0.0]
at weblogic.net.http.SOAPHttpURLConnection.getInputStream(SOAPHttpURLConnection.java:41)
~[wlfullclient.jar:12.2.2.0.0]
at ca.bell.webservice.WebServiceHandler.invokeWebService(WebServiceHandler.java:56)
[MigrationTool.jar:?]
at ca.bell.webservice.ExecuteMigrationWork.performRun(ExecuteMigrationWork.java:40)
[MigrationTool.jar:?]
at ca.bell.workmanagement.work.Work.call(Work.java:155) [MigrationTool.jar:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[?:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[?:1.8.0_131]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
答案 0 :(得分:0)
有趣。让我们从最近的异常来源开始分析堆栈跟踪。从AbstractPlainSocketImpl
的{{3}}开始,强制执行的第一个前提是:
public void setOption(int opt, Object val) throws SocketException {
if (isClosedOrPending()) {
throw new SocketException("Socket Closed");
}
...
由于HttpURLConnection
的范围仅限于方法invokeWebService
,我们可以排除套接字上并发操作的假设,因为它似乎很好并且没有关闭套接字,我相信isClosedOrPending
会返回true
,因为套接字的文件描述符是null
:
public boolean isClosedOrPending() {
/*
* Lock on fdLock to ensure that we wait if a
* close is in progress.
*/
synchronized (fdLock) {
if (closePending || (fd == null)) {
return true;
} else {
return false;
}
}
}
此分析中有疑问的是fd
文件描述符为null
的原因。但是,这在现阶段并不重要。如果我们相信我们的假设,我们可以得出的一个结论是,您为系统创建了太多的连接来处理。
我们如何解决这个问题?在这里,我们需要退一步,看看我们是否可以重构代码以限制并发连接的数量。我需要更多有关您具体实施的详细信息,以缩小设计候选人的范围,否则无限。例如,连接池是否合适?我们应该实施背压并扼杀客户吗?我们应该水平扩展并分配负载吗?