最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

AsyncHttpClient的ConnectionSemaphore方法源碼流程解讀

 更新時(shí)間:2023年12月07日 14:01:49   作者:codecraft  
這篇文章主要為大家介紹了AsyncHttpClient的ConnectionSemaphore方法源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本文主要研究一下AsyncHttpClient的ConnectionSemaphore

ConnectionSemaphore

org/asynchttpclient/netty/channel/ConnectionSemaphore.java

/**
 * Max connections and max-per-host connections limiter.
 *
 * @author Stepan Koltsov
 */
public class ConnectionSemaphore {
  private final NonBlockingSemaphoreLike freeChannels;
  private final int maxConnectionsPerHost;
  private final ConcurrentHashMap<Object, NonBlockingSemaphore> freeChannelsPerHost = new ConcurrentHashMap<>();
  private final IOException tooManyConnections;
  private final IOException tooManyConnectionsPerHost;
  private ConnectionSemaphore(AsyncHttpClientConfig config) {
    tooManyConnections = unknownStackTrace(new TooManyConnectionsException(config.getMaxConnections()), ConnectionSemaphore.class, "acquireChannelLock");
    tooManyConnectionsPerHost = unknownStackTrace(new TooManyConnectionsPerHostException(config.getMaxConnectionsPerHost()), ConnectionSemaphore.class, "acquireChannelLock");
    int maxTotalConnections = config.getMaxConnections();
    maxConnectionsPerHost = config.getMaxConnectionsPerHost();
    freeChannels = maxTotalConnections > 0 ?
            new NonBlockingSemaphore(config.getMaxConnections()) :
            NonBlockingSemaphoreInfinite.INSTANCE;
  }
  public static ConnectionSemaphore newConnectionSemaphore(AsyncHttpClientConfig config) {
    return config.getMaxConnections() > 0 || config.getMaxConnectionsPerHost() > 0 ? new ConnectionSemaphore(config) : null;
  }
  private boolean tryAcquireGlobal() {
    return freeChannels.tryAcquire();
  }
  private NonBlockingSemaphoreLike getFreeConnectionsForHost(Object partitionKey) {
    return maxConnectionsPerHost > 0 ?
            freeChannelsPerHost.computeIfAbsent(partitionKey, pk -> new NonBlockingSemaphore(maxConnectionsPerHost)) :
            NonBlockingSemaphoreInfinite.INSTANCE;
  }
  private boolean tryAcquirePerHost(Object partitionKey) {
    return getFreeConnectionsForHost(partitionKey).tryAcquire();
  }
  public void acquireChannelLock(Object partitionKey) throws IOException {
    if (!tryAcquireGlobal())
      throw tooManyConnections;
    if (!tryAcquirePerHost(partitionKey)) {
      freeChannels.release();
      throw tooManyConnectionsPerHost;
    }
  }
  public void releaseChannelLock(Object partitionKey) {
    freeChannels.release();
    getFreeConnectionsForHost(partitionKey).release();
  }
}
ConnectionSemaphore主要用于控制連接的maxConnections及maxConnectionsPerHost;它定義了freeChannels表示可用連接的信號(hào)量,定義了freeChannelsPerHost維護(hù)每個(gè)host的可用連接新用量,類型是NonBlockingSemaphoreLike;它提供了tryAcquireGlobal用于獲取全局的空閑連接,tryAcquirePerHost用于獲取指定host的空閑連接;acquireChannelLock先獲取全局空閑連接,獲取不到拋出TooManyConnectionsException,再獲取指定host的空閑連接,獲取不到則釋放全局空閑連接,拋出TooManyConnectionsPerHostException;releaseChannelLock則先釋放全局空閑連接,再釋放指定host的空閑連接

NonBlockingSemaphoreLike

org/asynchttpclient/netty/channel/NonBlockingSemaphoreLike.java

/**
 * Non-blocking semaphore API.
 *
 * @author Stepan Koltsov
 */
interface NonBlockingSemaphoreLike {
  void release();
  boolean tryAcquire();
}
NonBlockingSemaphoreLike接口定義了release、tryAcquire方法,它有兩個(gè)實(shí)現(xiàn)類,分別是NonBlockingSemaphore、NonBlockingSemaphoreInfinite

NonBlockingSemaphore

org/asynchttpclient/netty/channel/NonBlockingSemaphore.java

class NonBlockingSemaphore implements NonBlockingSemaphoreLike {
  private final AtomicInteger permits;
  NonBlockingSemaphore(int permits) {
    this.permits = new AtomicInteger(permits);
  }
  @Override
  public void release() {
    permits.incrementAndGet();
  }
  @Override
  public boolean tryAcquire() {
    for (; ; ) {
      int count = permits.get();
      if (count <= 0) {
        return false;
      }
      if (permits.compareAndSet(count, count - 1)) {
        return true;
      }
    }
  }
  @Override
  public String toString() {
    // mimic toString of Semaphore class
    return super.toString() + "[Permits = " + permits + "]";
  }
}
NonBlockingSemaphore內(nèi)部使用AtomicInteger來進(jìn)行控制,permits表示可用的數(shù)量,release方法則遞增permits,tryAcquire則循環(huán)執(zhí)行先判斷permits是否大于0,否則返回false,若permits.compareAndSet(count, count - 1)成功則返回true,否則繼續(xù)循環(huán)執(zhí)行直到返回false或者true

NonBlockingSemaphoreInfinite

org/asynchttpclient/netty/channel/NonBlockingSemaphoreInfinite.java

enum NonBlockingSemaphoreInfinite implements NonBlockingSemaphoreLike {
  INSTANCE;
  @Override
  public void release() {
  }
  @Override
  public boolean tryAcquire() {
    return true;
  }
  @Override
  public String toString() {
    return NonBlockingSemaphore.class.getName();
  }
}
NonBlockingSemaphoreInfinite表示無限的信號(hào)量,release為空操作,tryAcquire始終返回true

NettyResponseFuture

org/asynchttpclient/netty/NettyResponseFuture.java

/**
 * A {@link Future} that can be used to track when an asynchronous HTTP request
 * has been fully processed.
 *
 * @param <V> the result type
 */
public final class NettyResponseFuture<V> implements ListenableFuture<V> {
  //......
  public void acquirePartitionLockLazily() throws IOException {
    if (connectionSemaphore == null || partitionKeyLock != null) {
      return;
    }
    Object partitionKey = getPartitionKey();
    connectionSemaphore.acquireChannelLock(partitionKey);
    Object prevKey = PARTITION_KEY_LOCK_FIELD.getAndSet(this, partitionKey);
    if (prevKey != null) {
      // self-check
      connectionSemaphore.releaseChannelLock(prevKey);
      releasePartitionKeyLock();
      throw new IllegalStateException("Trying to acquire partition lock concurrently. Please report.");
    }
    if (isDone()) {
      // may be cancelled while we acquired a lock
      releasePartitionKeyLock();
    }
  }    
  public boolean cancel(boolean force) {
    releasePartitionKeyLock();
    cancelTimeouts();
    if (IS_CANCELLED_FIELD.getAndSet(this, 1) != 0)
      return false;
    // cancel could happen before channel was attached
    if (channel != null) {
      Channels.setDiscard(channel);
      Channels.silentlyCloseChannel(channel);
    }
    if (ON_THROWABLE_CALLED_FIELD.getAndSet(this, 1) == 0) {
      try {
        asyncHandler.onThrowable(new CancellationException());
      } catch (Throwable t) {
        LOGGER.warn("cancel", t);
      }
    }
    future.cancel(false);
    return true;
  }
  private boolean terminateAndExit() {
    releasePartitionKeyLock();
    cancelTimeouts();
    this.channel = null;
    this.reuseChannel = false;
    return IS_DONE_FIELD.getAndSet(this, 1) != 0 || isCancelled != 0;
  }    
  private void releasePartitionKeyLock() {
    if (connectionSemaphore == null) {
      return;
    }
    Object partitionKey = takePartitionKeyLock();
    if (partitionKey != null) {
      connectionSemaphore.releaseChannelLock(partitionKey);
    }
  }  
}
NettyResponseFuture提供了acquirePartitionLockLazily方法,它會(huì)通過connectionSemaphore.acquireChannelLock(partitionKey)來獲取連接信號(hào)量;cancel和terminateAndExit都會(huì)執(zhí)行releasePartitionKeyLock,它會(huì)調(diào)用connectionSemaphore.releaseChannelLock(partitionKey)

NettyRequestSender

org/asynchttpclient/netty/request/NettyRequestSender.java

public final class NettyRequestSender {
  private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class);
  private final AsyncHttpClientConfig config;
  private final ChannelManager channelManager;
  private final ConnectionSemaphore connectionSemaphore;
  private final Timer nettyTimer;
  private final AsyncHttpClientState clientState;
  private final NettyRequestFactory requestFactory;
  public NettyRequestSender(AsyncHttpClientConfig config,
                            ChannelManager channelManager,
                            Timer nettyTimer,
                            AsyncHttpClientState clientState) {
    this.config = config;
    this.channelManager = channelManager;
    this.connectionSemaphore = ConnectionSemaphore.newConnectionSemaphore(config);
    this.nettyTimer = nettyTimer;
    this.clientState = clientState;
    requestFactory = new NettyRequestFactory(config);
  }
  public <T> ListenableFuture<T> sendRequest(final Request request,
                                             final AsyncHandler<T> asyncHandler,
                                             NettyResponseFuture<T> future) {
    if (isClosed()) {
      throw new IllegalStateException("Closed");
    }
    validateWebSocketRequest(request, asyncHandler);
    ProxyServer proxyServer = getProxyServer(config, request);
    // WebSockets use connect tunneling to work with proxies
    if (proxyServer != null //
            && (request.getUri().isSecured() || request.getUri().isWebSocket()) //
            && !isConnectDone(request, future) //
            && proxyServer.getProxyType().isHttp()) {
      // Proxy with HTTPS or WebSocket: CONNECT for sure
      if (future != null && future.isConnectAllowed()) {
        // Perform CONNECT
        return sendRequestWithCertainForceConnect(request, asyncHandler, future, proxyServer, true);
      } else {
        // CONNECT will depend if we can pool or connection or if we have to open a new
        // one
        return sendRequestThroughSslProxy(request, asyncHandler, future, proxyServer);
      }
    } else {
      // no CONNECT for sure
      return sendRequestWithCertainForceConnect(request, asyncHandler, future, proxyServer, false);
    }
  }
  //......
}
NettyRequestSender的構(gòu)造器會(huì)根據(jù)配置創(chuàng)建ConnectionSemaphore,其sendRequest方法內(nèi)部調(diào)用的是sendRequestWithCertainForceConnect、sendRequestThroughSslProxy

sendRequestWithCertainForceConnect

/**
   * We know for sure if we have to force to connect or not, so we can build the
   * HttpRequest right away This reduces the probability of having a pooled
   * channel closed by the server by the time we build the request
   */
  private <T> ListenableFuture<T> sendRequestWithCertainForceConnect(Request request,
                                                                     AsyncHandler<T> asyncHandler,
                                                                     NettyResponseFuture<T> future,
                                                                     ProxyServer proxyServer,
                                                                     boolean performConnectRequest) {
    NettyResponseFuture<T> newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, proxyServer,
            performConnectRequest);
    Channel channel = getOpenChannel(future, request, proxyServer, asyncHandler);
    return Channels.isChannelActive(channel)
            ? sendRequestWithOpenChannel(newFuture, asyncHandler, channel)
            : sendRequestWithNewChannel(request, proxyServer, newFuture, asyncHandler);
  }
sendRequestWithCertainForceConnect方法先通過getOpenChannel獲取channel,然后執(zhí)行sendRequestWithOpenChannel或者sendRequestWithNewChannel

sendRequestThroughSslProxy

private <T> ListenableFuture<T> sendRequestThroughSslProxy(Request request,
                                                             AsyncHandler<T> asyncHandler,
                                                             NettyResponseFuture<T> future,
                                                             ProxyServer proxyServer) {
    NettyResponseFuture<T> newFuture = null;
    for (int i = 0; i < 3; i++) {
      Channel channel = getOpenChannel(future, request, proxyServer, asyncHandler);
      if (channel == null) {
        // pool is empty
        break;
      }
      if (newFuture == null) {
        newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, proxyServer, false);
      }
      if (Channels.isChannelActive(channel)) {
        // if the channel is still active, we can use it,
        // otherwise, channel was closed by the time we computed the request, try again
        return sendRequestWithOpenChannel(newFuture, asyncHandler, channel);
      }
    }
    // couldn't poll an active channel
    newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, proxyServer, true);
    return sendRequestWithNewChannel(request, proxyServer, newFuture, asyncHandler);
  }
sendRequestThroughSslProxy也是先通過getOpenChannel獲取channel,然后執(zhí)行sendRequestWithOpenChannel或者sendRequestWithNewChannel

sendRequestWithNewChannel

private <T> ListenableFuture<T> sendRequestWithNewChannel(Request request,
                                                            ProxyServer proxy,
                                                            NettyResponseFuture<T> future,
                                                            AsyncHandler<T> asyncHandler) {
    // some headers are only set when performing the first request
    HttpHeaders headers = future.getNettyRequest().getHttpRequest().headers();
    Realm realm = future.getRealm();
    Realm proxyRealm = future.getProxyRealm();
    requestFactory.addAuthorizationHeader(headers, perConnectionAuthorizationHeader(request, proxy, realm));
    requestFactory.setProxyAuthorizationHeader(headers, perConnectionProxyAuthorizationHeader(request, proxyRealm));
    future.setInAuth(realm != null && realm.isUsePreemptiveAuth() && realm.getScheme() != AuthScheme.NTLM);
    future.setInProxyAuth(
            proxyRealm != null && proxyRealm.isUsePreemptiveAuth() && proxyRealm.getScheme() != AuthScheme.NTLM);
    try {
      if (!channelManager.isOpen()) {
        throw PoolAlreadyClosedException.INSTANCE;
      }
      // Do not throw an exception when we need an extra connection for a
      // redirect.
      future.acquirePartitionLockLazily();
    } catch (Throwable t) {
      abort(null, future, getCause(t));
      // exit and don't try to resolve address
      return future;
    }
    resolveAddresses(request, proxy, future, asyncHandler)
            .addListener(new SimpleFutureListener<List<InetSocketAddress>>() {
              @Override
              protected void onSuccess(List<InetSocketAddress> addresses) {
                NettyConnectListener<T> connectListener = new NettyConnectListener<>(future,
                        NettyRequestSender.this, channelManager, connectionSemaphore);
                NettyChannelConnector connector = new NettyChannelConnector(request.getLocalAddress(),
                        addresses, asyncHandler, clientState);
                if (!future.isDone()) {
                  // Do not throw an exception when we need an extra connection for a redirect
                  // FIXME why? This violate the max connection per host handling, right?
                  channelManager.getBootstrap(request.getUri(), request.getNameResolver(), proxy)
                          .addListener((Future<Bootstrap> whenBootstrap) -> {
                            if (whenBootstrap.isSuccess()) {
                              connector.connect(whenBootstrap.get(), connectListener);
                            } else {
                              abort(null, future, whenBootstrap.cause());
                            }
                          });
                }
              }
              @Override
              protected void onFailure(Throwable cause) {
                abort(null, future, getCause(cause));
              }
            });
    return future;
  }
sendRequestWithNewChannel方法會(huì)執(zhí)行future.acquirePartitionLockLazily()來判斷連接是否超出限制,而sendRequestWithOpenChannel方法則沒有這一層判斷

小結(jié)

  • AsyncHttpClient通過ConnectionSemaphore來控制連接的maxConnections及maxConnectionsPerHost
  • NonBlockingSemaphore內(nèi)部使用AtomicInteger來進(jìn)行控制,permits表示可用的數(shù)量,release方法則遞增permits,tryAcquire則循環(huán)執(zhí)行先判斷permits是否大于0,否則返回false,若permits.compareAndSet(count, count - 1)成功則返回true,否則繼續(xù)循環(huán)執(zhí)行直到返回false或者true
  • NettyResponseFuture提供了acquirePartitionLockLazily方法,它會(huì)通過connectionSemaphore.acquireChannelLock(partitionKey)來獲取連接信號(hào)量;cancel和terminateAndExit都會(huì)執(zhí)行releasePartitionKeyLock,它會(huì)調(diào)用connectionSemaphore.releaseChannelLock(partitionKey)
  • NettyRequestSender的構(gòu)造器會(huì)根據(jù)配置創(chuàng)建ConnectionSemaphore,其sendRequest方法內(nèi)部調(diào)用的是sendRequestWithCertainForceConnect、sendRequestThroughSslProxy,它們都是先通過getOpenChannel獲取channel,然后根據(jù)channel是否active來執(zhí)行sendRequestWithOpenChannel或者sendRequestWithNewChannel;sendRequestWithNewChannel方法會(huì)執(zhí)行future.acquirePartitionLockLazily()來判斷連接是否超出限制,而sendRequestWithOpenChannel方法則沒有這一層判斷
綜上,AsyncHttpClient有定義了ChannelPool,不過其連接數(shù)的控制不是在ChannelPool里頭,而是通過ConnectionSemaphore來控制連接的maxConnections及maxConnectionsPerHost來執(zhí)行,它主要是在每次sendRequestWithNewChannel的時(shí)候進(jìn)行控制,先執(zhí)行future.acquirePartitionLockLazily()獲取允許,再進(jìn)行connect建立連接。

以上就是聊聊AsyncHttpClient的ConnectionSemaphore的詳細(xì)內(nèi)容,更多關(guān)于AsyncHttpClient的ConnectionSemaphore的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java微信公眾平臺(tái)開發(fā)(11) 微信三大平臺(tái)的關(guān)聯(lián)

    Java微信公眾平臺(tái)開發(fā)(11) 微信三大平臺(tái)的關(guān)聯(lián)

    這篇文章主要介紹了Java微信公眾平臺(tái)開發(fā)第十一步,微信開發(fā)中微信公眾平臺(tái)、開放平臺(tái)和商戶平臺(tái)的關(guān)聯(lián),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 批量將現(xiàn)有Jar包上傳到Maven私服

    批量將現(xiàn)有Jar包上傳到Maven私服

    今天小編就為大家分享一篇關(guān)于批量將現(xiàn)有Jar包上傳到Maven私服,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 利用Sharding-Jdbc進(jìn)行分庫(kù)分表的操作代碼

    利用Sharding-Jdbc進(jìn)行分庫(kù)分表的操作代碼

    sharding-jdbc是一個(gè)分布式的關(guān)系型數(shù)據(jù)庫(kù)中間件,今天通過本文給大家介紹利用Sharding-Jdbc進(jìn)行分庫(kù)分表的操作代碼,代碼簡(jiǎn)單易懂對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-01-01
  • Spring Boot配置讀取實(shí)現(xiàn)方法解析

    Spring Boot配置讀取實(shí)現(xiàn)方法解析

    這篇文章主要介紹了Spring Boot配置讀取實(shí)現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • java 文件上傳(單文件與多文件)

    java 文件上傳(單文件與多文件)

    這篇文章主要介紹了java 文件上傳(單文件與多文件)的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • SpringBoot開啟Swagger并配置基本信息方式

    SpringBoot開啟Swagger并配置基本信息方式

    這篇文章主要介紹了SpringBoot開啟Swagger并配置基本信息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot集成FastDFS+Nginx整合基于Token的防盜鏈的方法

    SpringBoot集成FastDFS+Nginx整合基于Token的防盜鏈的方法

    這篇文章主要介紹了SpringBoot集成FastDFS+Nginx整合基于Token的防盜鏈的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • java 愷撒加密/解密實(shí)現(xiàn)原理(附帶源碼)

    java 愷撒加密/解密實(shí)現(xiàn)原理(附帶源碼)

    本文介紹Java實(shí)現(xiàn)愷撒加密與解密,通過固定位移量對(duì)字母進(jìn)行循環(huán)替換,保留大小寫及非字母字符,由于其實(shí)現(xiàn)簡(jiǎn)單、易于理解,愷撒加密常被用作學(xué)習(xí)加密算法的入門案例,感興趣的朋友一起看看吧
    2025-08-08
  • 詳解Java方法method的定義與調(diào)用及重載

    詳解Java方法method的定義與調(diào)用及重載

    方法,也稱函數(shù),如果想要重復(fù)一段或者多段代碼塊的使用,可以將這些代碼封裝成一個(gè)方法,方法具體表現(xiàn)為某種行為,使用方法可以提高代碼的復(fù)用性
    2022-04-04
  • 淺談Java操作符與其優(yōu)先級(jí)

    淺談Java操作符與其優(yōu)先級(jí)

    這篇文章主要介紹了淺談Java操作符與其優(yōu)先級(jí),具有一定借鑒價(jià)值,需要的朋友可以了解下。
    2017-12-12

最新評(píng)論

铅山县| 漾濞| 永吉县| 达孜县| 宜川县| 绍兴县| 寻乌县| 明光市| 张北县| 房山区| 金昌市| 巴青县| 桃源县| 永川市| 深圳市| 夏河县| 广南县| 桦南县| 隆昌县| 苏州市| 江油市| 临泉县| 尼玛县| 凉城县| 海口市| 石城县| 盈江县| 新营市| 肥东县| 涟源市| 建瓯市| 崇州市| 白朗县| 探索| 瑞昌市| 灵山县| 太湖县| 化州市| 霍邱县| 枝江市| 房产|