在httpclient.execute中的HttpClientConnectionOperator.connect时忽略套接字读取超时

下面是jstack的输出,看线程,nid = 0x771d(30493)。 几个小时前就开始了。

"taskScheduler-6" prio=10 tid=0x00007f4479e07800 nid=0x771d runnable [0x00007f446e63a000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:152) at java.net.SocketInputStream.read(SocketInputStream.java:122) at sun.security.ssl.InputRecord.readFully(InputRecord.java:442) at sun.security.ssl.InputRecord.readV3Record(InputRecord.java:554) at sun.security.ssl.InputRecord.read(InputRecord.java:509) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:934) - locked  (a java.lang.Object) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332) - locked  (a java.lang.Object) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory .java:275) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java: 254) at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:1 23) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionMa nager.java:318) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) ........ // other call stack of custom codes 

并且线程的CPU时间总是相同的,而不是更改:(由top -Hp pid

  PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 30493 root 20 0 3832m 1.0g 11m S 0.0 2.2 0:01.20 java 

这是Java代码:

  RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(so_timeout_milliseconds) .setConnectTimeout(so_timeout_milliseconds).setSocketTimeout(so_timeout_milliseconds).build(); // so_timeout_milliseconds = 6000 do { CloseableHttpClient httpclient = HttpClients.createDefault(); try { HttpGet httpget = new HttpGet(url); httpget.setConfig(config); if (headers != null) { for (Header header : headers) { httpget.addHeader(header); } } CloseableHttpResponse response = httpclient.execute(httpget); // see jstack output above try { StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); try { return IOUtils.isToString(instream); } catch (IOException ex) { throw ex; } finally { instream.close(); } } } } finally { response.close(); } } finally { httpclient.close(); } } while (--try_times > 0); 

HttpClient版本:

   org.apache.httpcomponents httpclient 4.3.5  
  1. 我不确定这是HTTPClient中的错误吗? 如果是,部件代码会出现什么问题?
  2. 为什么线程RUNNABLE状态,并且CPU时间没有增加?

在我看来,这是因为IO无法完成,所以它不会发生CPU中断,但为什么状态不是SUSPEND 。(我的意思是在Java中WAITING )。

我找到了一个解决方案,将httpclient更新为4.3.6,问题解决了。 这是apache JIRA 。 更改的代码在这里 。

我不确定这是HTTPClient中的错误吗?

不会。任何这样的’bug’都会驻留在JVM中,而不是JSSE中,当然也不会存在于HTTPClient中。

如果是,部件代码会出现什么问题?

没有。 往上看。

为什么线程处于RUNNABLE状态,并且CPU时间没有增加?

作为RUNNABLE的Java线程意味着它不会被Java中的任何东西所阻碍,例如监视器或其他线程。 这并不意味着没有阻止操作系统的观点,例如在阻塞读取中,就像这里的情况一样。

在我看来,这是因为IO无法完成,所以不能发生CPU中断,但为什么状态不是SUSPEND。

没有 Thread.State.SUSPEND 这样的状态 。