第八天(okhttp之连接池)

okhttp的网络请求是基于socket请求,面不是原始的HttpConnection来操作的,但是Socket是很耗性能的,为什么Okhttp性能好速度快,是因为他有做网络请求缓存,还有一个就是他有一个连接池

连接池:主要目的就是把闲置一定时间的连接给中断.简单原理就是,创建一个线程池去做清理任务,这里是无限循环.

每当发现闲置时间超过设置的时间,就会把这个Socket连接给关闭.

还有一个就是每次发起一次请求的时候,他会去连接池里面找是否已经存在该连接,有的就复用.

这里我自己手写一个跟Okhttp类式的连接池 涉及到三个类

 

1: ConnectionPool2 这个是用来添加和获取请求连接对象
2:HttpConnection2 这个是连接对象
3:UserConnection2Pool 这个是连接池使用类

上面三个类中,最主要的还是ConnectionPool2这个类,

首先有几个成员变量

     /**
     * 检查机制
     * 每格一分钟,就去检查里面连接是否可用,不可用,移除
     */
    private long keepAlive;


    private boolean cleanRunnableFlag;//是否启动了清理任务

    //保存网络请求的队列
    private Deque<HttpConnection2> mHttpConnection2Deque = new ArrayDeque<>();

每当我们进行一个网络连接的时候,就会先判断队里里面是否有,没有就创建并将连接对象添加到队里里,所有就有put和get方法

    /**
     * 添加连接对象,到连接池里
     */
    public synchronized void putConnection(HttpConnection2 httpConnection2) {
        //一旦Put,就要检查要去清理
        if (!cleanRunnableFlag) {
            cleanRunnableFlag = true;
            mExecutor.execute(cleanRunnable);
        }
        mHttpConnection2Deque.add(httpConnection2);
    }

    /**
     * 获取连接对象,
     */
    public HttpConnection2 getConnection(String host, int port) {
        Iterator<HttpConnection2> iterator = mHttpConnection2Deque.iterator();
        while (iterator.hasNext()) {
            HttpConnection2 httpConnection2 = iterator.next();
            if (httpConnection2.itConnectionAction(host, port)) {
                //找到了
                Log.e("ConnectionPool2","找到了连接,复用一下");
                iterator.remove();
                return httpConnection2;
            }
        }
        return null;
    }

其实连接池最主要的还是怎么清理请求任务,下面代码

    /**
     * 开启一个线程,专门去检查连接池里面的(连接对象),无限循环
     */

    private Runnable cleanRunnable = new Runnable() {
        @Override
        public void run() {

            while (true) {
                long nextCleanTime = clean(System.currentTimeMillis());
                if (nextCleanTime == -1) {
                    cleanRunnableFlag = false;
                    return;
                }
                if (nextCleanTime > 0) {
                    //待一段时间再去清理
                    synchronized (ConnectionPool2.this) {
                        try {
                            ConnectionPool2.this.wait(nextCleanTime);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    };

    /**
     * 清理对象
     *
     * @param currentTimeMillis 当前时间
     */
    private long clean(long currentTimeMillis) {
        long idleRocordSave = -1;

        Iterator<HttpConnection2> iterator = mHttpConnection2Deque.iterator();
        while (iterator.hasNext()) {
            HttpConnection2 httpConnection2 = iterator.next();
            //我们添加的连接对象,超过了最大保持时间,移除连接对象
            long idleTime = currentTimeMillis - httpConnection2.lastUseTime;
            if (idleTime > keepAlive) {//大于最大的保持时间,将连接对象remove
                Log.e("ConnectionPool2","已经超过时间了,移除socket连接");
                iterator.remove();
                httpConnection2.closeSocket();
                continue;
            }
            //获得到最长的闲置时间,看连接闲置的最大值
            if (idleRocordSave < idleTime) {
                idleRocordSave = idleTime;
            }
        }
        if (idleRocordSave >= 0) {
            return keepAlive - idleRocordSave;
        }

        return idleRocordSave;
    }

所以,当时间过了设置的闲置时间就会将走

httpConnection2.closeSocket();这个方法也就是下面这些代码 
public void closeSocket() {
    if (mSocket != null) {
        try {
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这就实现了请求的复用和长连接的关闭,达到了节省服务器的压力.

 

OKhttp的连接池在哪里创建和在哪里使用

创建:当我们用builder创建OKHttpClient的时候这个时候就会创建一个连接池

 

哪里使用上了

RetryAndFollowUpInterceptor重试拦截器的intercept方法中,当创建一个StreamAllocation

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章