背景介绍

    项目中开启线程池下载图片,okhttp报错如下:
在这里插入图片描述
    一直沿用以前开发的工具类(将okhttp客户端封装成了单例模式),之前开发的项目涉及到的网络请求未出现过类似异常,而这次由于图片下载量大,线程数量多,造成socket超时。

    之前的工具类:

public class OkHttpUtils {

    private static volatile OkHttpClient client;

    private OkHttpUtils(){
    }

    public static OkHttpClient getInstance(){
        if (null==client){
            synchronized (OkHttpUtils.class){
                if (client==null){
                    client = new OkHttpClient.Builder()
                            .connectTimeout(10,TimeUnit.SECONDS)
                            .readTimeout(15, TimeUnit.SECONDS)
                            .writeTimeout(15, TimeUnit.MILLISECONDS)
                            .build();
                    return client;
                }
            }
        }
        return client;
    }
}

代码修改

    从异常报错看,是下载图片时发生的超时,推测主要是网络的原因(与下载图片的线程数量也间接有关),重新设置连接、读超时、及池化连接,这部分需阅读源码将最大空闲数和等待时间设大。由于项目中下载任务较多,且线程池中核心线程数量设置为10(考虑网络带宽,以免各种超时或图片下载不完整),最大线程数量设置为24。每个任务task中均调用OkHttpUtils.getInstance()获取okhttpClient对象,固在并发运行时需保证足够数量的okhttp连接。原来的代码底层用的默认值:连接池最大连接空闲数5,连接超时10秒,读写超时15秒。这里为保险起见,重新定义okhttp连接池最大空闲数量设为32,防止无连接可用等待超时后抛异常:

public class OkHttpUtils {

    private final static int READ_TIMEOUT = 100;

    private final static int CONNECT_TIMEOUT = 60;

    private final static int WRITE_TIMEOUT = 60;

    private static volatile OkHttpClient okHttpClient;

    private OkHttpUtils(){

        okhttp3.OkHttpClient.Builder clientBuilder = new okhttp3.OkHttpClient.Builder();
        //读取超时
        clientBuilder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
        //连接超时
        clientBuilder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
        //写入超时
        clientBuilder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
        //自定义连接池最大空闲连接数和等待时间大小,否则默认最大5个空闲连接
        clientBuilder.connectionPool(new ConnectionPool(32,5,TimeUnit.MINUTES));

        okHttpClient = clientBuilder.build();
    }

    public static OkHttpClient getInstance(){
        if (null == okHttpClient){
            synchronized (OkHttpUtils.class){
                if (okHttpClient == null){
                    new OkHttpUtils();
                    return okHttpClient;
                }
            }
        }
        return okHttpClient;
    }
}

总结

    修改后异常消失。实际上,超时时间、等待时间、线程数量需根据项目实际需求进行调整。另外,网络原因有时很难控制,所以确保业务安全,还需在相关业务流程中加TRY-CATCH-REDO-FINALLY或TRY-CATCH-TODO-FINALLY逻辑,如下载失败则重新下载或记录日志等等。

参考

https://sq.163yun.com/blog/article/188729834576564224
https://blog.csdn.net/sun20209527/article/details/79377513

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐