jedis的borrow行為方法源碼解讀
序
本文主要研究一下jedis的borrow行為
borrowObject
org/apache/commons/pool2/impl/GenericObjectPool.java
public T borrowObject(final Duration borrowMaxWaitDuration) throws Exception { assertOpen(); final AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getRemoveAbandonedOnBorrow() && (getNumIdle() < 2) && (getNumActive() > getMaxTotal() - 3)) { removeAbandoned(ac); } PooledObject<T> p = null; // Get local copy of current config so it is consistent for entire // method execution final boolean blockWhenExhausted = getBlockWhenExhausted(); boolean create; final long waitTimeMillis = System.currentTimeMillis(); while (p == null) { create = false; p = idleObjects.pollFirst(); if (p == null) { p = create(); if (p != null) { create = true; } } if (blockWhenExhausted) { if (p == null) { if (borrowMaxWaitDuration.isNegative()) { p = idleObjects.takeFirst(); } else { p = idleObjects.pollFirst(borrowMaxWaitDuration); } } if (p == null) { throw new NoSuchElementException(appendStats( "Timeout waiting for idle object, borrowMaxWaitDuration=" + borrowMaxWaitDuration)); } } else if (p == null) { throw new NoSuchElementException(appendStats("Pool exhausted")); } if (!p.allocate()) { p = null; } if (p != null) { try { factory.activateObject(p); } catch (final Exception e) { try { destroy(p, DestroyMode.NORMAL); } catch (final Exception e1) { // Ignore - activation failure is more important } p = null; if (create) { final NoSuchElementException nsee = new NoSuchElementException( appendStats("Unable to activate object")); nsee.initCause(e); throw nsee; } } if (p != null && getTestOnBorrow()) { boolean validate = false; Throwable validationThrowable = null; try { validate = factory.validateObject(p); } catch (final Throwable t) { PoolUtils.checkRethrow(t); validationThrowable = t; } if (!validate) { try { destroy(p, DestroyMode.NORMAL); destroyedByBorrowValidationCount.incrementAndGet(); } catch (final Exception e) { // Ignore - validation failure is more important } p = null; if (create) { final NoSuchElementException nsee = new NoSuchElementException( appendStats("Unable to validate object")); nsee.initCause(validationThrowable); throw nsee; } } } } } updateStatsBorrow(p, Duration.ofMillis(System.currentTimeMillis() - waitTimeMillis)); return p.getObject(); }
- borrowObject方法會開啟一個while循環(huán),條件是p為null,也就是要獲取到p或者是內(nèi)部自己跳出循環(huán);idleObjects.pollFirst()從連接池獲取,如果為null則執(zhí)行create,之后是blockWhenExhausted的判斷邏輯,如果create出來的為null,則阻塞等待takeFirst或者pollFirst(borrowMaxWaitDuration),如果還是null則拋出NoSuchElementException;如果blockWhenExhausted為false但是create為null則拋出
Pool exhausted
- 如果不是null,則再次確認下object的狀態(tài),如果變更狀態(tài)(
PooledObjectState.IDLE-->PooledObjectState.ALLOCATED
)不成功則返回null;接著執(zhí)行factory.activateObject(p)方法,如果出現(xiàn)異常則destory掉(jedis這里只是在db不一樣的時候會重新select,默認可以理解為空操作),緊接著是testOnBorrow的邏輯 - 這里就是如果idleObjects.pollFirst()為null會觸發(fā)create,如果還是null則直接拋出NoSuchElementException異常,跳出循環(huán);只有在不為null且allocate失敗的時候會重置為null繼續(xù)循環(huán);另外如果是create出來的但是activate不成功也會拋出NoSuchElementException異常,跳出循環(huán)
create
/** * Attempts to create a new wrapped pooled object. * <p> * If there are {@link #getMaxTotal()} objects already in circulation * or in process of being created, this method returns null. * </p> * * @return The new wrapped pooled object * * @throws Exception if the object factory's {@code makeObject} fails */ private PooledObject<T> create() throws Exception { int localMaxTotal = getMaxTotal(); // This simplifies the code later in this method if (localMaxTotal < 0) { localMaxTotal = Integer.MAX_VALUE; } final long localStartTimeMillis = System.currentTimeMillis(); final long localMaxWaitTimeMillis = Math.max(getMaxWaitDuration().toMillis(), 0); // Flag that indicates if create should: // - TRUE: call the factory to create an object // - FALSE: return null // - null: loop and re-test the condition that determines whether to // call the factory Boolean create = null; while (create == null) { synchronized (makeObjectCountLock) { final long newCreateCount = createCount.incrementAndGet(); if (newCreateCount > localMaxTotal) { // The pool is currently at capacity or in the process of // making enough new objects to take it to capacity. createCount.decrementAndGet(); if (makeObjectCount == 0) { // There are no makeObject() calls in progress so the // pool is at capacity. Do not attempt to create a new // object. Return and wait for an object to be returned create = Boolean.FALSE; } else { // There are makeObject() calls in progress that might // bring the pool to capacity. Those calls might also // fail so wait until they complete and then re-test if // the pool is at capacity or not. makeObjectCountLock.wait(localMaxWaitTimeMillis); } } else { // The pool is not at capacity. Create a new object. makeObjectCount++; create = Boolean.TRUE; } } // Do not block more if maxWaitTimeMillis is set. if (create == null && (localMaxWaitTimeMillis > 0 && System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) { create = Boolean.FALSE; } } if (!create.booleanValue()) { return null; } final PooledObject<T> p; try { p = factory.makeObject(); if (getTestOnCreate() && !factory.validateObject(p)) { createCount.decrementAndGet(); return null; } } catch (final Throwable e) { createCount.decrementAndGet(); throw e; } finally { synchronized (makeObjectCountLock) { makeObjectCount--; makeObjectCountLock.notifyAll(); } } final AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getLogAbandoned()) { p.setLogAbandoned(true); p.setRequireFullStackTrace(ac.getRequireFullStackTrace()); } createdCount.incrementAndGet(); allObjects.put(new IdentityWrapper<>(p.getObject()), p); return p; }
create方法不會判斷createCount,如果超出則返回null,如果等待超出maxWait也會返回null;如果判斷要創(chuàng)建則通過factory.makeObject(),另外針對testOnCreate且validateObject不通過的也返回null,如果是有異常則直接拋出
makeObject
redis/clients/jedis/JedisFactory.java
@Override public PooledObject<Jedis> makeObject() throws Exception { Jedis jedis = null; try { jedis = new Jedis(jedisSocketFactory, clientConfig); jedis.connect(); return new DefaultPooledObject<>(jedis); } catch (JedisException je) { if (jedis != null) { try { jedis.quit(); } catch (RuntimeException e) { logger.warn("Error while QUIT", e); } try { jedis.close(); } catch (RuntimeException e) { logger.warn("Error while close", e); } } throw je; } }
JedisFactory的makeObject會創(chuàng)建Jedis然后執(zhí)行connect,如果有JedisException則拋出,這個也會直接跳出borrowObject的循環(huán),直接給到調(diào)用方
activateObject
redis/clients/jedis/JedisFactory.java
public void activateObject(PooledObject<Jedis> pooledJedis) throws Exception { final BinaryJedis jedis = pooledJedis.getObject(); if (jedis.getDB() != clientConfig.getDatabase()) { jedis.select(clientConfig.getDatabase()); } }
JedisFactory的activateObject就是判斷db跟配置的是不是一樣,不一樣則重新select
testOnBorrow
if (p != null && getTestOnBorrow()) { boolean validate = false; Throwable validationThrowable = null; try { validate = factory.validateObject(p); } catch (final Throwable t) { PoolUtils.checkRethrow(t); validationThrowable = t; } if (!validate) { try { destroy(p, DestroyMode.NORMAL); destroyedByBorrowValidationCount.incrementAndGet(); } catch (final Exception e) { // Ignore - validation failure is more important } p = null; if (create) { final NoSuchElementException nsee = new NoSuchElementException( appendStats("Unable to validate object")); nsee.initCause(validationThrowable); throw nsee; } } } public static void checkRethrow(final Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } // All other instances of Throwable will be silently swallowed }
testOnBorrow的邏輯就是執(zhí)行validateObject方法,如果是ThreadDeath或者VirtualMachineError才會重新拋出,否則吞掉,之后判斷validate結果,如果不成功則執(zhí)行destory方法,重新設置為null,但是如果這個是create出來的則拋出NoSuchElementException
小結
jedis的borrow行為是在while循環(huán)里頭去獲取的,一般是在allocate變更狀態(tài)不成功(PooledObjectState.IDLE-->PooledObjectState.ALLOCATED
)的時候會重新設置null,繼續(xù)循環(huán)
- idleObjects.pollFirst()為null會觸發(fā)create,如果還是null則拋出NoSuchElementException(
Pool exhausted
)跳出循環(huán);如果blockWhenExhausted為true,block之后獲取到的還是null,也會拋出NoSuchElementException(Timeout waiting for idle object
)跳出循環(huán);如果觸發(fā)create操作,且create拋出JedisException,這個也會直接跳出borrowObject的循環(huán),直接給到調(diào)用方 - borrow出來不會null的執(zhí)行activateObject,jedis這里只是在db不一樣的時候會重新select,默認可以理解為空操作
最后是testOnBorrow的邏輯,如果有異常,則針對create出來的則拋出NoSuchElementException跳出循環(huán),否則重置為null繼續(xù)循環(huán)
總結
一下就是如果是create有異常(JedisException
)則直接拋出,如果borrow不到(即使經(jīng)過create)也會拋出NoSuchElementException(具體可能是Pool exhausted或者Timeout waiting for idle object),如果有testOnBorrow不通過且是create出來的,也會拋出NoSuchElementException(Unable to validate object
)
以上就是jedis的borrow行為方法源碼解讀的詳細內(nèi)容,更多關于jedis borrow方法的資料請關注腳本之家其它相關文章!
相關文章
老生常談Java中List與ArrayList的區(qū)別
大家都知道List是接口,ArrayList是List接口的一個實現(xiàn)類,接下來通過本文給大家介紹Java中List與ArrayList的區(qū)別,需要的朋友可以參考下2022-08-08java?SpringBoot?分布式事務的解決方案(JTA+Atomic+多數(shù)據(jù)源)
這篇文章主要介紹了java?SpringBoot?分布式事務的解決方案(JTA+Atomic+多數(shù)據(jù)源),文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下2022-08-08HashMap實現(xiàn)保存兩個key相同的數(shù)據(jù)
這篇文章主要介紹了HashMap實現(xiàn)保存兩個key相同的數(shù)據(jù)操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06基于ElasticSearch Analyzer的使用規(guī)則詳解
這篇文章主要介紹了基于ElasticSearch Analyzer的使用規(guī)則,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07