HttpClient线程池原理
1.cpool对象
- class CPool extends AbstractConnPool<HttpRoute, ManagedHttpClientConnection, CPoolEntry> {
- private static final AtomicLong COUNTER = new AtomicLong();
- private final Log log = LogFactory.getLog(CPool.class);
- private final long timeToLive;
- private final TimeUnit tunit;
- public CPool(
- final ConnFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
- final int defaultMaxPerRoute, final int maxTotal,
- final long timeToLive, final TimeUnit tunit) {
- super(connFactory, defaultMaxPerRoute, maxTotal);
- this.timeToLive = timeToLive;
- this.tunit = tunit;
- }
- HttpRoute, ManagedHttpClientConnection, CPoolEntry
- public abstract class AbstractConnPool<T, C, E extends PoolEntry<T, C>>
- implements ConnPool<T, E>, ConnPoolControl<T> {
- private final Lock lock;
- private final ConnFactory<T, C> connFactory;
- private final Map<T, RouteSpecificPool<T, C, E>> routeToPool;
- private final Set<E> leased;
- private final LinkedList<E> available;
- private final LinkedList<PoolEntryFuture<E>> pending;
- private final Map<T, Integer> maxPerRoute;
- private volatile boolean isShutDown;
- private volatile int defaultMaxPerRoute;
- private volatile int maxTotal;
- private volatile int validateAfterInactivity;
先看从线程池里面是如何过去链接的
图一
- @Override
- public Future<E> lease(final T route, final Object state, final FutureCallback<E> callback) {
- Args.notNull(route, "Route");
- Asserts.check(!this.isShutDown, "Connection pool shut down");
- return new PoolEntryFuture<E>(this.lock, callback) {
- @Override
- public E getPoolEntry(
- final long timeout,
- final TimeUnit tunit)
- throws InterruptedException, TimeoutException, IOException {
- final E entry = getPoolEntryBlocking(route, state, timeout, tunit, this);
- onLease(entry);
- return entry;
- }
- };
- }
这儿每次都会返回一个futrue对象。
这个对象就是PoolEntryFuture对象,可以看到里面的get方法
- public T get(
- final long timeout,
- final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- Args.notNull(unit, "Time unit");
- this.lock.lock();
- try {
- if (this.completed) {
- return this.result;
- }
- this.result = getPoolEntry(timeout, unit);
- this.completed = true;
- if (this.callback != null) {
- this.callback.completed(this.result);
- }
- return result;
- } catch (final IOException ex) {
- this.completed = true;
- this.result = null;
- if (this.callback != null) {
- this.callback.failed(ex);
- }
- throw new ExecutionException(ex);
- } finally {
- this.lock.unlock();
- }
- }
这里的getPoolEntry方法,正是上图中红色字体标明的内部类实现的方法
而我们继续追踪AbstractConnPool类的getPoolEntryBlocking方法,这个就是从连接池中取出来链接,如果取不到,就进入等待队列,当有连接释放时,在尝试去获取连接
- private E getPoolEntryBlocking(
- final T route, final Object state,
- final long timeout, final TimeUnit tunit,
- final PoolEntryFuture<E> future)
- throws IOException, InterruptedException, TimeoutException {
- Date deadline = null;
- if (timeout > 0) {
- deadline = new Date
- (System.currentTimeMillis() + tunit.toMillis(timeout));
- }
- this.lock.lock();
- try {
- final RouteSpecificPool<T, C, E> pool = getPool(route);
- E entry = null;
- while (entry == null) {
- Asserts.check(!this.isShutDown, "Connection pool shut down");
- for (;;) {
- entry = pool.getFree(state);
- if (entry == null) {
- break;
- }
- if (entry.isClosed() || entry.isExpired(System.currentTimeMillis())) {
- entry.close();
- this.available.remove(entry);
- pool.free(entry, false);
- } else {
- break;
- }
- }
- if (entry != null) {
- this.available.remove(entry);
- this.leased.add(entry);
- return entry;
- }
- // New connection is needed
- final int maxPerRoute = getMax(route);
- // Shrink the pool prior to allocating a new connection
- final int excess = Math.max(0, pool.getAllocatedCount() + 1 - maxPerRoute);
- if (excess > 0) {
- for (int i = 0; i < excess; i++) {
- final E lastUsed = pool.getLastUsed();
- if (lastUsed == null) {
- break;
- }
- lastUsed.close();
- this.available.remove(lastUsed);
- pool.remove(lastUsed);
- }
- }
- if (pool.getAllocatedCount() < maxPerRoute) {
- final int totalUsed = this.leased.size();
- final int freeCapacity = Math.max(this.maxTotal - totalUsed, 0);
- if (freeCapacity > 0) {
- final int totalAvailable = this.available.size();
- if (totalAvailable > freeCapacity - 1) {
- if (!this.available.isEmpty()) {
- final E lastUsed = this.available.removeLast();
- lastUsed.close();
- final RouteSpecificPool<T, C, E> otherpool = getPool(lastUsed.getRoute());
- otherpool.remove(lastUsed);
- }
- }
- final C conn = this.connFactory.create(route);
- entry = pool.add(conn);
- this.leased.add(entry);
- return entry;
- }
- }
- boolean success = false;
- try {
- pool.queue(future);
- this.pending.add(future);
- success = future.await(deadline); //如果获取不到连接就等待
- } finally {
- // In case of 'success', we were woken up by the
- // connection pool and should now have a connection
- // waiting for us, or else we're shutting down.
- // Just continue in the loop, both cases are checked.
- pool.unqueue(future);
- this.pending.remove(future);
- }
- // check for spurious wakeup vs. timeout
- if (!success && (deadline != null) &&
- (deadline.getTime() <= System.currentTimeMillis())) {
- break;
- }
- }
- throw new TimeoutException("Timeout waiting for connection");
- } finally {
- this.lock.unlock();
- }
- }