马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
说下场景,我的程序在多线程场景下一个循环体中处理业务数据,其中需要调用一个外部http接口去获取一些数据,程序总会在在本地执行一段时间后会抛出Address already in use: no further information错误。
这是大量并发场景下出现的问题,经过查阅原因是OkHttp的链接没有被有效回收和复用导致的端口资源占用,okHttp在发起请求调用外部接口时也会占用本地的端口资源,因为okHttp需要建立Socket链接来和对方通信,端口是本地一个随机的未被使用的端口,okHttp会尽量复用这些资源以减少服务器消耗,但如果在短时间内出现大量的请求都在创建新的okHttp对象去发起请求,那么每个okHttp对象的资源占用都不会共享,导致资源被浪费,亦或者没有及时关闭响应体,比如response.close()。最终,资源被耗尽,出现 Address already in use: no further information。而我的调用代码就是为了图方便简单的每次请求创建一个新的OkHttpClient
解决方式很简单,使用单例的OkHttpClient并配置好超时时间,同时注意资源关闭,如果是在Spring环境下做个配置就行,其中线程数和连接回收时间根据自己情况进行调整:- @Configuration
- public class HttpClientConfiguration {
- @Bean
- public OkHttpClient httpClient(){
- return new OkHttpClient().newBuilder()
- //设置线程池 最大200线程 最大保持10秒连接既自动回收
- .connectionPool(new ConnectionPool(200, 10, TimeUnit.SECONDS))
- //设置超时时间
- .connectTimeout(5, TimeUnit.SECONDS).readTimeout(5,TimeUnit.SECONDS)
- .writeTimeout(5,TimeUnit.SECONDS).build();
- }
- }
-
-
- class Test{
-
- @Autowired
- private OkHttpClient httpClient;
-
- public JsonNode getFieldData(String token){
- String body = "{xxx}";
-
- RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"),body);
- Request request = new Request.Builder().url("http://xxxx").post(requestBody).header("token",token).build();
-
- //请求成功结果正常则返回数据
- try (Response response = httpClient.newCall(request).execute()){
- if(response.isSuccessful()){
- String resultJsonStr = response.body().string();
- JsonNode resJson = objectMapper.readTree(resultJsonStr);
- return resJson.get("result");
- }
- }catch (Exception e){
- logger.error(e.getMessage(),e);
- }
- return objectMapper.createObjectNode();
- }
- }
复制代码 另外,根据找到的资料,单例模式下的OkHttp性能也会更好:
如果okhttp客户端不是单例的,那么每次发送请求时都会创建一个新的客户端对象,这样会导致资源浪费和性能下降,而且可能会导致内存泄漏。okhttp客户端是设计成单例的,它可以共享连接池、响应缓存和配置。因此,建议使用单例模式来创建和管理okhttp客户端,或者至少为每个主机名保持一个客户端实例。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |