天天看點

BUG記錄 —— Java 使用HTTPClient出現死鎖

這兩天碰到一個奇怪的問題,Java在使用HTTPClient的時候,多調用了幾次,然後就出現死鎖,程式停到client.execute(httpget); 不往下走,也不抛異常。堆棧資訊報錯如下:

java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
           

解決方法往下看:

問題描述:

Java在使用HTTPClient的時候,多調用了幾次,然後就出現死鎖,程式停到client.execute(httpget); 不往下走,也不抛異常

問題定位:

首先發現消息隊列的消費速率從200/s變為20/s(630個線程在跑);

檢視之後發現630個線程都在,但是隻有7~8個線程在工作,其他線程都是在死鎖中;

檢視堆棧資訊,發現線程那些死鎖的線程的報錯資訊:

java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
        at sun.security.ssl.InputRecord.read(InputRecord.java:503)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
        - locked <0x00000005d08557b8> (a java.lang.Object)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
        - locked <0x00000005d0855a58> (a java.lang.Object)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
        at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.upgrade(DefaultHttpClientConnectionOperator.java:192)
        at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.upgrade(PoolingHttpClientConnectionManager.java:369)
        at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:415)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        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:107)
        at com.tomtop.big.data.crawler.express.utils.HttpClientUtil.doGetProxyHeader(HttpClientUtil.java:514)
        at com.tomtop.big.data.crawler.express.jobs.chinapost.ChinaPostApiTrack.emsGetFromBaidu(ChinaPostApiTrack.java:138)
        at com.tomtop.big.data.crawler.express.jobs.chinapost.ChinaPostApiTrack.run(ChinaPostApiTrack.java:112)
        at com.tomtop.big.data.crawler.code.mq.QueueOneLitener.onMessage(QueueOneLitener.java:35)
        at sun.reflect.GeneratedMethodAccessor99.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:269)
        at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:387)
        at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:298)
        at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:777)
        at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:700)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:95)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:187)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1187)
        at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:681)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1165)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1149)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1100(SimpleMessageListenerContainer.java:95)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1312)
        at java.lang.Thread.run(Thread.java:748)
           

接下來就是在往上找資料解決問題喽~

問題解決:

1、網上一大把人說是因為傳回消息未關閉,so試一下:response.getEntity().getContent().close();

然而問題并沒有解決(沮喪)。。。。

2、繼續查資料發現有位大佬說是JDK1.8-210之前的版本的BUG:

https://stackoverflow.com/questions/25968769/got-stuck-at-java-net-socketinputstream-socketread0native-method

3、so 換新的JDK版本1.8-212(問題沒有解決)

4、問題規避:a) 使用Http連接配接池做連接配接重用; b) 使用線程池管理線程,并為所有線程建立心跳線程,長時間未傳回結果則強行關閉。

繼續閱讀