OkHttp源码阅读(二)Dispatcher

Dispatcher做的事很简单

默认包含一个corePollSize为0的线程池,闲置一段时间后所有线程都会销毁

还有三个队列,等待请求的队列、异步请求中的队列、同步请求中的队列

设置并发数量限制,不断把readyAsyncCalls中请求往runningAsyncCalls中添加,所有请求结束时回调idleCallback

public final class Dispatcher {
    private int maxRequests = 64;//最大并发请求数
    private int maxRequestsPerHost = 5;//正在请求的队列(runningAsyncCalls)中,相同host的请求的最大数量
    Runnable idleCallback;//Dispatcher闲置回调函数
    private @Nullable ExecutorService executorService;
    /**
     * Ready async calls in the order they'll be run. 
     * 将要请求的异步请求队列
     */
    private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>();
    /** 
     * Running asynchronous calls. Includes canceled calls that haven't finished yet. 
     * 正在请求的异步请求队列,包含已经取消但是还没有结束的请求
     */
    private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>();
    /** 
     * Running synchronous calls. Includes canceled calls that haven't finished yet. 
     * 正在请求的同步请求队列,包含已经取消但是还没有结束的请求
     */
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

    public Dispatcher(ExecutorService executorService) {
        this.executorService = executorService;
    }

    public Dispatcher() {
    }

    public synchronized ExecutorService executorService() {
        if (executorService == null) {
            executorService = new ThreadPoolExecutor(
	        //corePoolSize:最小并发线程数,这里并发同时包括空闲与活动的线程,如果是0的话,空闲一段时间后所有线程将全部被销毁。
			0,
		//maximumPoolSize:最大线程数,当任务进来时可以扩充的线程最大值,当大于了这个值就会根据丢弃处理机制来处理 
			Integer.MAX_VALUE,
		//keepAliveTime:当线程数大于corePoolSize时,多余的空闲线程的最大存活时间,类似于HTTP中的Keep-alive 
			60,
                 //TimeUnit unit:时间单位,一般用秒
			TimeUnit.SECONDS,
		//工作队列
			new SynchronousQueue<Runnable>(), 
		//ThreadFactory threadFactory:单个线程的工厂,可以打Log,设置Daemon(即当JVM退出时,线程自动结束)等
			Util.threadFactory("OkHttp Dispatcher", false)
		);
        }
        return executorService;
    }

    /**
     * 设置最大并发线程数,超过这个数量的请求要等runningAsyncCalls中的请求执行完成
     * Set the maximum number of requests to execute concurrently. Above this requests queue in
     * memory, waiting for the running calls to complete.
     * <p>If more than {@code maxRequests} requests are in flight when this is invoked, those requests
     * will remain in flight.
     */
    public synchronized void setMaxRequests(int maxRequests) {
        if (maxRequests < 1) {
            throw new IllegalArgumentException("max < 1: " + maxRequests);
        }
        this.maxRequests = maxRequests;
	//从readyAsyncCalls中取出请求,放入runningAsyncCalls,直到达到最大请求数限制
        promoteCalls();
    }

    public synchronized int getMaxRequests() {
        return maxRequests;
    }

    /**
     * 设置每个host请求的最大并发线程数,根据url的host来限制请求 
     * 请注意,对单个IP地址的并发请求可能仍然超出此限制:多个主机名可能共享IP地址或通过相同的HTTP代理进行路由。
     * 如果超过{@code maxRequestsPerHost}请求在被调用时处于运行状态,那么这些请求将保持在运行状态。
     * Set the maximum number of requests for each host to execute concurrently. This limits requests
     * by the URL's host name. Note that concurrent requests to a single IP address may still exceed
     * this limit: multiple hostnames may share an IP address or be routed through the same HTTP
     * proxy.
     * <p>If more than {@code maxRequestsPerHost} requests are in flight when this is invoked, those
     * requests will remain in flight.
     */
    public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
        if (maxRequestsPerHost < 1) {
            throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
        }
        this.maxRequestsPerHost = maxRequestsPerHost;
	//从readyAsyncCalls中取出请求,放入runningAsyncCalls,直到达到最大请求数限制
        promoteCalls();
    }

    public synchronized int getMaxRequestsPerHost() {
        return maxRequestsPerHost;
    }

    /**
     * 设置闲置回调函数,当dispatcher闲置时的回调函数(running calls返回数量为0时回调)
     * 请求闲置的时间根据执行的是同步请求还是异步请求有差异
     * 异步请求在onResponse或onFailure回调后才闲置,同步请求一旦执行execute()就闲置。
     * Set a callback to be invoked each time the dispatcher becomes idle (when the number of running
     * calls returns to zero).
     * <p>Note: The time at which a {@linkplain Call call} is considered idle is different depending
     * on whether it was run {@linkplain Call#enqueue(Callback) asynchronously} or
     * {@linkplain Call#execute() synchronously}. Asynchronous calls become idle after the
     * {@link Callback#onResponse onResponse} or {@link Callback#onFailure onFailure} callback has
     * returned. Synchronous calls become idle once {@link Call#execute() execute()} returns. This
     * means that if you are doing synchronous calls the network layer will not truly be idle until
     * every returned {@link Response} has been closed.
     */
    public synchronized void setIdleCallback(@Nullable Runnable idleCallback) {
        this.idleCallback = idleCallback;
    }

    synchronized void enqueue(RealCall.AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        //请求添加到runningAsyncCalls中,并用线程池执行请求
	    runningAsyncCalls.add(call);
            executorService().execute(call);
        } else {//runningAsyncCalls中并发请求达到上限,或者runningAsyncCalls中与call的host相同的请求达到上限,则把请求添加到readyAsyncCalls
            readyAsyncCalls.add(call);
        }
    }

    /**
     * 取消所有请求,包括同步请求、异步请求、等待中的请求、执行中的请求
     * call.get().cancel()实际上调用的是retryAndFollowUpInterceptor.cancel() -> StreamAllocation.cancel() -> closeQuietly(rawSocket);
     */
    public synchronized void cancelAll() {
        for (RealCall.AsyncCall call : readyAsyncCalls) {
            call.get().cancel();
        }
        for (RealCall.AsyncCall call : runningAsyncCalls) {
            call.get().cancel();
        }
        for (RealCall call : runningSyncCalls) {
            call.cancel();
        }
    }

    //从readyAsyncCalls中取出请求,往runningAsyncCalls中塞
    private void promoteCalls() {
        if (runningAsyncCalls.size() >= maxRequests) {
            return; // Already running max capacity.
        }
        if (readyAsyncCalls.isEmpty()) {
            return; // No ready calls to promote.
        }
	//遍历等待请求的队列readyAsyncCalls
        for (Iterator<RealCall.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
            RealCall.AsyncCall call = i.next();//readyAsyncCalls的请求
	//runningAsyncCalls中与call的host相同的请求数量,小于同一host并发的最大数量限制时
            if (runningCallsForHost(call) < maxRequestsPerHost) {
                i.remove();//把该call从readyAsyncCalls中移除,添加到runningAsyncCalls中
                runningAsyncCalls.add(call);
                executorService().execute(call);//然后让线程池执行请求
            }
	//当runningAsyncCalls达到最大并发请求数时,打断循环,不再往runningAsyncCalls添加
            if (runningAsyncCalls.size() >= maxRequests) {
                return; // Reached max capacity.
            }
        }
    }

    /** 
     * 返回正在请求的异步队列中host与call的host相同的数量
     * Returns the number of running calls that share a host with {@code call}. 
     */
    private int runningCallsForHost(RealCall.AsyncCall call) {
        int result = 0;
        for (RealCall.AsyncCall c : runningAsyncCalls) {
            if (c.host().equals(call.host())) {
                result++;
            }
        }
        return result;
    }

    /** 
     * okHttpClient.newCall(request).execute()内部调用的就是这个dispatcher.execute(call)
     * 把请求添加到队列中
     */
    synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
    }

    /** Used by {@code AsyncCall#run} to signal completion. */
    void finished(RealCall.AsyncCall call) {
        finished(runningAsyncCalls, call, true);
    }

    /** Used by {@code Call#execute} to signal completion. */
    void finished(RealCall call) {
        finished(runningSyncCalls, call, false);
    }
    /**
     * 每执行完一个请求,会调用该方法把已执行的请求从队列中移除
     */
    private <T> void finished(Deque<T> 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();//触发闲置回调
        }
    }

    /** Returns a snapshot of the calls currently awaiting execution. */
    public synchronized List<Call> queuedCalls() {
        List<Call> result = new ArrayList<>();
        for (RealCall.AsyncCall asyncCall : readyAsyncCalls) {
            result.add(asyncCall.get());
        }
        return Collections.unmodifiableList(result);
    }

    /** Returns a snapshot of the calls currently being executed. */
    public synchronized List<Call> runningCalls() {
        List<Call> result = new ArrayList<>();
        result.addAll(runningSyncCalls);
        for (RealCall.AsyncCall asyncCall : runningAsyncCalls) {
            result.add(asyncCall.get());
        }
        return Collections.unmodifiableList(result);
    }

    public synchronized int queuedCallsCount() {
        return readyAsyncCalls.size();
    }

    public synchronized int runningCallsCount() {
        return runningAsyncCalls.size() + runningSyncCalls.size();
    }
}
在实际请求中的调用:okHttpClient.newCall(request).execute();
@Override
public Response execute() throws IOException {
      synchronized (this) {
            if (executed) {
                throw new IllegalStateException("Already Executed");
            }
            executed = true;
      }
      captureCallStackTrace();
      try {
       //由此可见execute方法真正执行的是dispatcher.execute(call);
           client.dispatcher().executed(this);
            Response result = getResponseWithInterceptorChain();
            if (result == null) {
                throw new IOException("Canceled");
            }
            return result;
      } finally {
        //执行完成之后调用dispatcher.finished(call)把该已执行完的请求从队列中移除
           client.dispatcher().finished(this);
      }
}

注意一个小点:cancelAll()执行路径:

1、call.get().cancel() -> retryAndFollowUpInterceptor.cancel() -> StreamAllocation.cancel() -> closeQuietly(rawSocket)

取消任务,实际上是关闭socket。

2、socket的关闭不影响连接池的复用,每次连接时都会创建socket的(http1.1),http2.0对相同host的请求可以共用一个socket

RealConnection.connect() -> connectSocket() {
...
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
        ? address.socketFactory().createSocket()//创建的socket
        : new Socket(proxy);//使用代理创建socket
...
//打开socket连接
Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
...//处理输入输出流(Okio)
} -> establishProtocol() - >connectTls() {
...
socket = sslSocket
...
}

3、 正常执行完请求也是要关闭socket的,http请求用的是短连接,有些人不明所以,对取消请求时关闭socket大呼耗性能,真是可笑。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值