天天看点

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) 使用线程池管理线程,并为所有线程创建心跳线程,长时间未返回结果则强行关闭。

继续阅读