美文网首页okhttp
了解OKHttp线程池实现原理

了解OKHttp线程池实现原理

作者: Xiuz_hmy | 来源:发表于2018-11-05 17:30 被阅读0次

1、在OKHttp中需要一个队列来保存不同的请求

/**
 * 保存HttpConnection队列
 */
private Deque<HttpConnection> mConnections = new ArrayDeque<>();

2、在每次请求前从线程池里检查是否有超时的连接,将超时的连接从线程池移除

//在这里将连接放入线程池
public void put(HttpConnection httpConnection) {
    if (!cleanupRunning) {
        cleanupRunning = true;
        EXECUTOR.execute(cleanupRunnable);
    }
    mConnections.add(httpConnection);
}

/**
 * 清理线程
 */
private Runnable cleanupRunnable = () -> {
    while(true) {
        //等待再次检查时间间隔
        long waitTime = cleanup(System.currentTimeMillis());

        if(waitTime == -1) {
            return;
        }

        if(waitTime > 0) {
            synchronized (ConnectionPool.this){
                try {
                    ConnectionPool.this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
};


   //在这里清理超时请求
   private long cleanup(long nowTime) {
    //记录最长闲置时间
    long longLastIdlTime = -1;
    synchronized (this) {
        //遍历连接队列
        Iterator<HttpConnection> iterator = mConnections.iterator();
        while (iterator.hasNext()) {
            HttpConnection next = iterator.next();
            //闲置时间
            long idlDurationTime = nowTime - next.getLastUseTime();
            if (idlDurationTime > keepAlive) {
                iterator.remove();
                next.close();
                Log.d(TAG, "cleanup —> 超过闲置时间,移出线程池");
                continue;
            }

            //最长的闲置时间
            if (longLastIdlTime < idlDurationTime) {
                longLastIdlTime = idlDurationTime;
            }
        }
        //返回等待时间
        if (longLastIdlTime >= 0) {
            return keepAlive - longLastIdlTime;
        }
        //连接池没有连接,可以退出
        cleanupRunning = false;
        return longLastIdlTime;
    }
}

3、清理线程由线程池管理并将线程设为守护线程

/**
 * 定义一个线程池,用来执行清理线程
 */
private static final Executor EXECUTOR 
    = new ThreadPoolExecutor(
        0, //最小并发线程数。
        Integer.MAX_VALUE, //线程池中允许的最大线程数
        60L, //当线程的数目大于corePoolSize时,线程的最大存活时间。
        TimeUnit.SECONDS, //时间单位
        new SynchronousQueue<>(),//在执行任务之前用于保存任务的队列
        r -> {//创建新的线程使用的工厂
           Thread thread = new Thread(r, "ConnectionPool");
           thread.setDaemon(true);
           return thread;
});

4、线程池的复用,遍历请求队列的请求,判断是否有相同的请求

/**
 * 获得可复用的连接池
 *
 * @param host
 * @param port
 * @return
 */
public HttpConnection get(String host, int port) {
    Iterator<HttpConnection> iterator = mConnections.iterator();
    while (iterator.hasNext()) {
        HttpConnection next = iterator.next();
        //判断线程池里是否存在相同的请求地址
        if (next.isSameAdress(host, port)) {
            iterator.remove();
            return next;
        }
    }
    return null;
}


public boolean isSameAdress(String host, int port) {
    if (TextUtils.isEmpty(host) || port < 0) {
        throw new NullPointerException("Host OR Port maybe null point,Please Check it once again");
    }
    if (mSocket == null) {
        return false;
    }
    return TextUtils.equals(host, mSocket.getInetAddress().getHostName()) && port == mSocket.getPort();
}

相关文章

网友评论

    本文标题:了解OKHttp线程池实现原理

    本文链接:https://www.haomeiwen.com/subject/sbasxqtx.html