Okhttp任务队列工作原理

应用层:
1.讲请求添加到分发起中 Client.dispatcher().executed(this);
2.创建截获器ApplicationInterceptorChain(可对请求进行压缩,修改编码等处理)
逻辑层
1.数据缓存:
1)缓存的数据没有过期,直接使用
2)缓存的数据过期,先用过期的,再去网络请求数据,并更新本地数据
3)缓存的数据没有,去网络直接获取
2.底层使用连接池
3.路线选择器(路由选择,选择最优)
4.网络截获器可以有多个(依据目标地址是否有重定向来觉得)
链路层
1.底层是Socket

1 概述
1.1 线程池ThreadPoolExecutor
ThreadPoolExecutor是java线程创建工具。存在于java.util.concurrent 包中。
看构造方法:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
  • corePoolSize : 最小并发线程数。
  • maximumPoolSize :线程池中最大的线程池并发数。
  • keepAliveTime : 当线程的数目大于
  • corePoolSize时,线程的最大存活时间。
  • unit : 时间单位 BlockingQueue 工作队列

okhttp的线程池对象存在于Dispatcher类中。实例过程如下:

public synchronized ExecutorService executorService() {
        if (executorService == null) {
            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
        }
        return executorService;
    }

1.2 Call对象
okttp的操作元是Call对象。异步的实现是RealCall.AsyncCall。而 AsyncCall是实现的一个Runnable接口。所以Call本质就是一个Runable线程操作元肯定是放进excutorService中直接启动的。

final class AsyncCall extends NamedRunnable {}
private final Deque readyAsyncCalls = new ArrayDeque<>();
private final Deque runningAsyncCalls = new ArrayDeque<>();

2.2 过程分析
Call代用enqueue方法的时候

synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            runningAsyncCalls.add(call);
            executorService().execute(call);
        } else {
            readyAsyncCalls.add(call);
        }
    }

方法中满足执行队列里面不足最大线程数maxRequests并且Call对应的host数目不超过maxRequestsPerHost 的时候直接把call对象直接推入到执行队列里,并启动线程任务(Call本质是一个Runnable)。否则,当前线程数过多,就把他推入到等待队列中。Call执行完肯定需要在runningAsyncCalls 队列中移除这个线程。那么readyAsyncCalls队列中的线程在什么时候才会被执行呢。

追溯下AsyncCall 线程的执行方法

@Override
    protected void execute() {
        boolean signalledCallback = false;
        try {
            Response response = getResponseWithInterceptorChain(forWebSocket);
            if (canceled) {
                signalledCallback = true;
                responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
            } else {
                signalledCallback = true;
                responseCallback.onResponse(RealCall.this, response);
            }
        } catch (IOException e) {
            if (signalledCallback) {// Do not signal the callback twice!   
                Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
            } else {
                responseCallback.onFailure(RealCall.this, e);
            }
        } finally {
            client.dispatcher().finished(this);
        }
    }

这里做了核心request的动作,并把失败和回复数据的结果通过responseCallback 回调到Dispatcher。执行操作完毕了之后不管有无异常都会进入到dispactcher的finished方法。

private  void finished(Deque calls, T call, boolean promoteCalls) {
        int runningCallsCount;
        Runnable idleCallback;
        synchronized (this) {
            if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
            if (promoteCalls) promoteCalls();
            runningCallsCount = runningCallsCount();
            idleCallback = this.idleCallback;
        }
        if (runningCallsCount == 0 && idleCallback != null) {
            idleCallback.run();
        }
    }

在这里call在runningAsyncCalls队列中被移除了,重新计算了目前正在执行的线程数量。并且调用了promoteCalls() 看来是来调整任务队列的

private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests)
        return; //
    if (readyAsyncCalls.isEmpty()) return;
    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall call = i.next();
        if (runningCallsForHost(call) < maxRequestsPerHost) {
            i.remove();
            runningAsyncCalls.add(call);
            executorService().execute(call);
        }
        if (runningAsyncCalls.size() >= maxRequests) return;
    }
}

原来实在这里对readyAsyncCalls 进行调度的。最终会在readyAsyncCalls 中通过remove操作把最后一个元素取出并移除之后加入到runningAsyncCalls的执行队列中执行操作。ArrayDeque 是非线程安全的所以finished在调用promoteCalls 的时候都在synchronized块中执行的。执行等待队列线程当然的前提是runningAsyncCalls 线程数没有超上线,而且等待队列里面有等待的任务。

小结,Call在执行任务通过Dispatcher把单元任务优先推到执行队列里进行操作,如果操作完成再执行等待队列的任务。

你可能感兴趣的:(android)