OKHTTP3源码解读:Dispatcher任务分发队列

本文详细解析了OkHttp中的Dispatcher组件,阐述了其线程池管理机制,包括最大请求限制、任务队列处理流程,以及同步与异步请求的执行策略。同时,探讨了任务取消机制和线程池空闲状态的回调处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、基本介绍:

  • Dispatcher持有一个线程池和三个可代表的线程维护的队列,并提供了add,remove,cancel三个性质的方法。
  • 只不过这个取消的方法交给了拦截器RetryAndFollowUpInterceptor处理,拦截器会调用coneation.canel()进行传输层的握手中断。

2、Dispatcher类:

	public final class Dispatcher {
	  private int maxRequests = 64;
	  private int maxRequestsPerHost = 5;
	  private Runnable idleCallback;
	
	  /** Executes calls. Created lazily. */
	  //任务队列线程池
	  private ExecutorService executorService;
	
	  /** Ready async calls in the order they'll be run. */
	    //待执行异步任务队列
	  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
	
	  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ 
	  //运行中异步任务队列【最大64】
	  private final Deque<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(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
	          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
	    }
	    return executorService;
	  }
	  
	  ...
	}
	
1、在Okhttp中,构建了一个阀值为[0, Integer.MAX_VALUE]的线程池,它不保留任何最小线程数,随时创建更多的线程数,当线程空闲时只能活60秒,它使用了一个不存储元素的阻塞工作队列,一个叫做"OkHttp Dispatcher"的线程工厂。
2、也就是说,在实际运行中,当收到10个并发请求时,线程池会创建十个线程,当工作完成后,线程池会在60s后相继关闭所有线程。
	        

3、同步请求:

	  synchronized void Dispatcher#executed(RealCall call) {
	    runningSyncCalls.add(call);
	  }

4、异步请求:

	synchronized void  Dispatcher#enqueue(AsyncCall call) {
	    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
	      runningAsyncCalls.add(call);
	         //线程池执行请求
	      executorService().execute(call);
	    } else {
	      readyAsyncCalls.add(call);
	    }
	  }
	
1、当前请求数小于最大请求数(64,对单一host的请求小于阈值(5:将该任务插入正在执行任务队列,并执行对应任务。
2、如果不满足则将其放入待执行队列。

5、结束任务:

	private <T> void Dispatcher#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();
	    }
	  }
	
1、每次调用Call的execute()方法执行完都会调用这个方法。
2、从正在运行的任务队列calls中删除任务call。
3、一般异步任务的promoteCalls会传ture,这时会调用promoteCalls()把readyAsyncCalls中的任务移到runningAsyncCalls中并执行。
4、如果当前整个线程池都空闲下来,执行空闲通知回调线程idleCallback.run( )

6、将等待任务队列添加到运行任务队列:

private void Dispatcher#promoteCalls() {
	    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
	    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
	    for (Iterator<AsyncCall> 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; // Reached max capacity.
	    }
	  }
1、每次用户重新设置最大maxRequests、maxRequestsPerHost时都会调用。
2、将满足条件的等待任务从readyAsyncCalls删除,添加到runningAsyncCalls并立即执行该任务:遍历待执行任务队列readyAsyncCalls,如果runningAsyncCalls队列call数量小于maxRequests,并且readyAsyncCalls中的等待任务call的host所对应的请求任务数量小于maxRequestsPerHost,则将readyAsyncCalls中的该等待任务call添加到runningAsyncCalls,并调用线程池去执行该call。

7、取消任务:

public synchronized void cancelAll() {
    for (AsyncCall call : readyAsyncCalls) {
      call.get().cancel();
    }

    for (AsyncCall call : runningAsyncCalls) {
      call.get().cancel();
    }

    for (RealCall call : runningSyncCalls) {
      call.cancel();
    }
  }

1、取消的方法交给了拦截器RetryAndFollowUpInterceptor处理,拦截器会调用coneation.canel()进行传输层的握手中断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值