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方法會(huì)開啟一個(gè)while循環(huán),條件是p為null,也就是要獲取到p或者是內(nèi)部自己跳出循環(huán);idleObjects.pollFirst()從連接池獲取,如果為null則執(zhí)行create,之后是blockWhenExhausted的判斷邏輯,如果create出來(lái)的為null,則阻塞等待takeFirst或者pollFirst(borrowMaxWaitDuration),如果還是null則拋出NoSuchElementException;如果blockWhenExhausted為false但是create為null則拋出
Pool exhausted - 如果不是null,則再次確認(rèn)下object的狀態(tài),如果變更狀態(tài)(
PooledObjectState.IDLE-->PooledObjectState.ALLOCATED)不成功則返回null;接著執(zhí)行factory.activateObject(p)方法,如果出現(xiàn)異常則destory掉(jedis這里只是在db不一樣的時(shí)候會(huì)重新select,默認(rèn)可以理解為空操作),緊接著是testOnBorrow的邏輯 - 這里就是如果idleObjects.pollFirst()為null會(huì)觸發(fā)create,如果還是null則直接拋出NoSuchElementException異常,跳出循環(huán);只有在不為null且allocate失敗的時(shí)候會(huì)重置為null繼續(xù)循環(huán);另外如果是create出來(lái)的但是activate不成功也會(huì)拋出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方法不會(huì)判斷createCount,如果超出則返回null,如果等待超出maxWait也會(huì)返回null;如果判斷要?jiǎng)?chuàng)建則通過(guò)factory.makeObject(),另外針對(duì)testOnCreate且validateObject不通過(guò)的也返回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會(huì)創(chuàng)建Jedis然后執(zhí)行connect,如果有JedisException則拋出,這個(gè)也會(huì)直接跳出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才會(huì)重新拋出,否則吞掉,之后判斷validate結(jié)果,如果不成功則執(zhí)行destory方法,重新設(shè)置為null,但是如果這個(gè)是create出來(lái)的則拋出NoSuchElementException
小結(jié)
jedis的borrow行為是在while循環(huán)里頭去獲取的,一般是在allocate變更狀態(tài)不成功(PooledObjectState.IDLE-->PooledObjectState.ALLOCATED)的時(shí)候會(huì)重新設(shè)置null,繼續(xù)循環(huán)
- idleObjects.pollFirst()為null會(huì)觸發(fā)create,如果還是null則拋出NoSuchElementException(
Pool exhausted)跳出循環(huán);如果blockWhenExhausted為true,block之后獲取到的還是null,也會(huì)拋出NoSuchElementException(Timeout waiting for idle object)跳出循環(huán);如果觸發(fā)create操作,且create拋出JedisException,這個(gè)也會(huì)直接跳出borrowObject的循環(huán),直接給到調(diào)用方 - borrow出來(lái)不會(huì)null的執(zhí)行activateObject,jedis這里只是在db不一樣的時(shí)候會(huì)重新select,默認(rèn)可以理解為空操作
最后是testOnBorrow的邏輯,如果有異常,則針對(duì)create出來(lái)的則拋出NoSuchElementException跳出循環(huán),否則重置為null繼續(xù)循環(huán)
總結(jié)
一下就是如果是create有異常(JedisException)則直接拋出,如果borrow不到(即使經(jīng)過(guò)create)也會(huì)拋出NoSuchElementException(具體可能是Pool exhausted或者Timeout waiting for idle object),如果有testOnBorrow不通過(guò)且是create出來(lái)的,也會(huì)拋出NoSuchElementException(Unable to validate object)
以上就是jedis的borrow行為方法源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于jedis borrow方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java線程池ExecutorService超時(shí)處理小結(jié)
使用ExecutorService時(shí),設(shè)置子線程執(zhí)行超時(shí)是一個(gè)常見需求,本文就來(lái)詳細(xì)的介紹一下ExecutorService超時(shí)的三種方法,感興趣的可以了解一下2024-09-09
java web實(shí)現(xiàn)自動(dòng)登錄
這篇文章主要為大家詳細(xì)介紹了java web實(shí)現(xiàn)自動(dòng)登錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
老生常談Java中List與ArrayList的區(qū)別
大家都知道List是接口,ArrayList是List接口的一個(gè)實(shí)現(xiàn)類,接下來(lái)通過(guò)本文給大家介紹Java中List與ArrayList的區(qū)別,需要的朋友可以參考下2022-08-08
java?SpringBoot?分布式事務(wù)的解決方案(JTA+Atomic+多數(shù)據(jù)源)
這篇文章主要介紹了java?SpringBoot?分布式事務(wù)的解決方案(JTA+Atomic+多數(shù)據(jù)源),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-08-08
HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)
這篇文章主要介紹了HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
基于ElasticSearch Analyzer的使用規(guī)則詳解
這篇文章主要介紹了基于ElasticSearch Analyzer的使用規(guī)則,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Java8 新特性Lambda表達(dá)式實(shí)例詳解
這篇文章主要介紹了Java8 新特性Lambda表達(dá)式實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03
java中Integer包裝類裝箱的一個(gè)細(xì)節(jié)詳解
Java中的Integer是int的包裝類型,下面這篇文章主要給大家介紹了關(guān)于java中Integer包裝類裝箱的一個(gè)細(xì)節(jié)的相關(guān)資料,文中介紹的這個(gè)細(xì)節(jié)挺重要的,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起看看吧2018-07-07
Java Springboot之Spring家族的技術(shù)體系
今天帶大家來(lái)學(xué)習(xí)Spring家族的技術(shù)體系,文中有非常詳細(xì)的圖文介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05

