這兩天碰到一個奇怪的問題,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) 使用線程池管理線程,并為所有線程建立心跳線程,長時間未傳回結果則強行關閉。