OkHttp源碼分析(二)-----------------分發器Dispatcher

Dispatcher簡介

分發器,又稱爲調度器,是OkHttp中核心的一個類,維護着所有請求的狀態,並且在類中維護一個線程池,用來執行請求,關於其具體使用可參見OkHttp源碼分析(一)

Dispatcher成員變量

public final class Dispatcher {
   //最大併發請求數
   private int maxRequests = 64;
   //每個主機最大請求數
   private int maxRequestsPerHost = 5;
   private @Nullable Runnable idleCallback;
   //線程池用來維護執行請求和等待請求 
   private @Nullable ExecutorService executorService;
   //異步的等待隊列
   private final Deque<AsyncCall> readyAsyncCalls = new  
     ArrayDeque<>();
   //異步的執行隊列
   private final Deque<AsyncCall> runningAsyncCalls = new    
     ArrayDeque<>();
   //同步的執行隊列
   private final Deque<RealCall> runningSyncCalls = new  
     ArrayDeque<>();

   ........
}

異步執行時Dispatcher的工作機制

異步執行其實調用的是RealCall#enqueue方法如下所示

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  //注意這裏調用的dispatcher的enqueue方法
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

接着來看Dispatcher#enqueue

synchronized void enqueue(AsyncCall call) {
  //先判斷是否超過相應的閾值,即是最大併發請求數,每個主機最大請求數
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    //若是沒有超過,添加請求到執行的隊列中
    runningAsyncCalls.add(call);
    //使用線程池去執行該請求     ---------------(1)
    executorService().execute(call);
  } else {
    //否則就放到等待的隊列中
    readyAsyncCalls.add(call);
  }
}

(1)我們先來看看executorService()方法:

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;
}

上述過程中我們可以看到異步請求的時候是啓用線程池去執行任務的,那麼現在來具體是怎麼執行,我們注意到上述中的executorService().execute(call)方法中傳入的參數是AsyncCall類型,那麼見RealCall#AsyncCall源碼如下:

final class AsyncCall extends NamedRunnable {
  private final Callback responseCallback;

  AsyncCall(Callback responseCallback) {
    super("OkHttp %s", redactedUrl());
    this.responseCallback = responseCallback;
  }

  ......

  //執行任務
  @Override protected void execute() {
    try {
    //中間內容分析詳見《OkHttp源碼分析(一)》
      ......
      Response response = getResponseWithInterceptorChain();
      ......

    } catch (IOException e) {
      ......  
    } finally {
      //執行完畢之後要銷燬請求,回收資源
      client.dispatcher().finished(this);
    }
  }
}

可以看到執行完成之後是一定會執行Dispatcher#finished,所以接下來要做的就是分析一下finished方法源碼

/** Used by {@code AsyncCall#run} to signal completion. */
void finished(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!");
    //判斷是是否需將Call從等待隊列中提升到執行隊列中
    if (promoteCalls) promoteCalls();  //-------------(1)
    //獲取正在執行中的call,包括同步和異步
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
  }

  if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
  }
}

(1)Dispathcer#promoteCalls方法:

private void promoteCalls() {
  //等待隊列runningAsyncCalls已經滿了,沒有辦法添加請求
  if (runningAsyncCalls.size() >= maxRequests) return; 
  //等待隊列中沒有被等待執行的請求
  if (readyAsyncCalls.isEmpty()) return; 
  //遍歷等待隊列,獲取請求
  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator();   i.hasNext(); ) {
   AsyncCall call = i.next();
   //判斷該請求的host是否小於每個host最大請求閾值
   if (runningCallsForHost(call) < maxRequestsPerHost) {
     i.remove();
     //若是沒有則將該請求添加到執行隊列runningAsyncCalls中,並通過線程池執行該請求
     runningAsyncCalls.add(call);
     executorService().execute(call);
   }
   //同理,若是遍歷過程中執行隊列數量已滿,則終止遍歷
   if (runningAsyncCalls.size() >= maxRequests) return; 
 }
}

至此當等待隊列readyAsyncCalls中所有的請求執行完成之後return結束。

同步執行時Dispatcher的工作機制

//其中原理和異步執行一樣不再詳述
@Override public Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  try {
    //添加請求到Dispatcher中
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
  } finally {
    //請求完成之後,銷燬此call,回收資源
    client.dispatcher().finished(this);
  }
}

Dispatcher的工作機制流程圖

這裏寫圖片描述
圖片來源:https://blog.csdn.net/qq_16445551/article/details/78979306

Dispathcer對外的一些方法

cancelAll()

//結束掉所有的請求,包括同步、異步、等待隊列中的請求
public synchronized void cancelAll() {
    for (AsyncCall call : readyAsyncCalls) {
      call.get().cancel();
    }

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

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

queuedCalls()

//返回當前的等待執行的請求
public synchronized List<Call> queuedCalls() {
   List<Call> result = new ArrayList<>();
   for (AsyncCall asyncCall : readyAsyncCalls) {
     result.add(asyncCall.get());
   }
   return Collections.unmodifiableList(result);
}

runningCalls()

//返回當前正在執行隊列的中的請求
 public synchronized List<Call> runningCalls() {
   List<Call> result = new ArrayList<>();
   result.addAll(runningSyncCalls);
   for (AsyncCall asyncCall : runningAsyncCalls) {
     result.add(asyncCall.get());
   }
   return Collections.unmodifiableList(result);
 }

queuedCallsCount()

 //返回當前等待隊列中請求的數量
 public synchronized int queuedCallsCount() {
    return readyAsyncCalls.size();
 }

runningCallsCount()

//返回執行隊列中的請求數量,包括異步、同步
public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章