第八天(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

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