socket连接代理导致线程阻塞处理
系统中使用了socket连接代理系统,但运行了一阵后发现线程池中的线程一直在稳定增长。其间出现过一次RejectedExecutionException。
导出线程栈如下,随后将服务禁用,再次导出依然大量线程处于下列状态。说明有很多线程阻塞在socketRead0上。
3822 java.lang.Thread.State: RUNNABLE
3823 at java.net.SocketInputStream.socketRead0(Native Method)
3824 at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
3825 at java.net.SocketInputStream.read(SocketInputStream.java:170)
3826 at java.net.SocketInputStream.read(SocketInputStream.java:141)
3827 at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
3828 at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
3829 at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
3830 - locked <0x0000000643def6d8> (a java.io.BufferedInputStream)
3831 at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:704)
3832 at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647)
3833 at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:2000)
3834 - locked <0x0000000643def730> (a sun.net.www.protocol.http.HttpURLConnection)
3835 at sun.reflect.GeneratedMethodAccessor29.invoke(Unknown Source)
3836 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
3837 at java.lang.reflect.Method.invoke(Method.java:497)
3838 at java.net.HttpConnectSocketImpl.doTunneling(HttpConnectSocketImpl.java:179)
3839 at java.net.HttpConnectSocketImpl.doTunnel(HttpConnectSocketImpl.java:168)
3840 at java.net.HttpConnectSocketImpl.access$200(HttpConnectSocketImpl.java:44)
3841 at java.net.HttpConnectSocketImpl$2.run(HttpConnectSocketImpl.java:151)
3842 at java.net.HttpConnectSocketImpl$2.run(HttpConnectSocketImpl.java:149)
3843 at java.security.AccessController.doPrivileged(Native Method)
3844 at java.net.HttpConnectSocketImpl.privilegedDoTunnel(HttpConnectSocketImpl.java:148)
3845 at java.net.HttpConnectSocketImpl.connect(HttpConnectSocketImpl.java:111)
3846 at java.net.Socket.connect(Socket.java:589)
socket连接代理的代码为
this.socket = new Socket(proxy);
this.socket.connect(new InetSocketAddress(host, port),confCenter.getSocketConnectTimeout());
this.socket.setSoTimeout(confCenter.getSocketReadTimeout());
结合http代理建立原理(下图来自http权威指南)和调用栈可知,connect过程中存在read操作,因此setSoTimeout应该置于connect之前。修改后重启服务,观察一段时间系统恢复正常,线程池中的线程处在一个稳定的数值上。