欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

jedis的testWhileIdle用法源碼解讀

 更新時(shí)間:2023年09月24日 08:48:04   作者:codecraft  
這篇文章主要為大家介紹了jedis的testWhileIdle用法源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本文主要研究一下jedis的testWhileIdle

testWhileIdle

org/apache/commons/pool2/impl/GenericObjectPool.java

@Override
    public void evict() throws Exception {
        assertOpen();
        if (!idleObjects.isEmpty()) {
            PooledObject<T> underTest = null;
            final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
            synchronized (evictionLock) {
                final EvictionConfig evictionConfig = new EvictionConfig(
                        getMinEvictableIdleDuration(),
                        getSoftMinEvictableIdleDuration(),
                        getMinIdle());
                final boolean testWhileIdle = getTestWhileIdle();
                for (int i = 0, m = getNumTests(); i < m; i++) {
                    if (evictionIterator == null || !evictionIterator.hasNext()) {
                        evictionIterator = new EvictionIterator(idleObjects);
                    }
                    if (!evictionIterator.hasNext()) {
                        // Pool exhausted, nothing to do here
                        return;
                    }
                    try {
                        underTest = evictionIterator.next();
                    } catch (final NoSuchElementException nsee) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        evictionIterator = null;
                        continue;
                    }
                    if (!underTest.startEvictionTest()) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        continue;
                    }
                    // User provided eviction policy could throw all sorts of
                    // crazy exceptions. Protect against such an exception
                    // killing the eviction thread.
                    boolean evict;
                    try {
                        evict = evictionPolicy.evict(evictionConfig, underTest,
                                idleObjects.size());
                    } catch (final Throwable t) {
                        // Slightly convoluted as SwallowedExceptionListener
                        // uses Exception rather than Throwable
                        PoolUtils.checkRethrow(t);
                        swallowException(new Exception(t));
                        // Don't evict on error conditions
                        evict = false;
                    }
                    if (evict) {
                        destroy(underTest, DestroyMode.NORMAL);
                        destroyedByEvictorCount.incrementAndGet();
                    } else {
                        if (testWhileIdle) {
                            boolean active = false;
                            try {
                                factory.activateObject(underTest);
                                active = true;
                            } catch (final Exception e) {
                                destroy(underTest, DestroyMode.NORMAL);
                                destroyedByEvictorCount.incrementAndGet();
                            }
                            if (active) {
                                boolean validate = false;
                                Throwable validationThrowable = null;
                                try {
                                    validate = factory.validateObject(underTest);
                                } catch (final Throwable t) {
                                    PoolUtils.checkRethrow(t);
                                    validationThrowable = t;
                                }
                                if (!validate) {
                                    destroy(underTest, DestroyMode.NORMAL);
                                    destroyedByEvictorCount.incrementAndGet();
                                    if (validationThrowable != null) {
                                        if (validationThrowable instanceof RuntimeException) {
                                            throw (RuntimeException) validationThrowable;
                                        }
                                        throw (Error) validationThrowable;
                                    }
                                } else {
                                    try {
                                        factory.passivateObject(underTest);
                                    } catch (final Exception e) {
                                        destroy(underTest, DestroyMode.NORMAL);
                                        destroyedByEvictorCount.incrementAndGet();
                                    }
                                }
                            }
                        }
                        if (!underTest.endEvictionTest(idleObjects)) {
                            // TODO - May need to add code here once additional
                            // states are used
                        }
                    }
                }
            }
        }
        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
            removeAbandoned(ac);
        }
    }
GenericObjectPool的evict方法在idleObjects不為空的時(shí)候會執(zhí)行evict邏輯,它先通過getNumTests獲取每次要對多少個(gè)idleObject進(jìn)行驗(yàn)證,之后循環(huán)處理,首先通過evictionPolicy.evict判斷是否需要evict,如果是則執(zhí)行destroy方法,否則判斷是否testWhileIdle,若是則先執(zhí)行activateObject方法,再執(zhí)行validateObject,如果activateObject或者validateObject失敗則執(zhí)行destroy方法,如果validateObject成功則執(zhí)行passivateObject方法

JedisFactory

redis/clients/jedis/JedisFactory.java

@Override
  public void activateObject(PooledObject<Jedis> pooledJedis) throws Exception {
    final BinaryJedis jedis = pooledJedis.getObject();
    if (jedis.getDB() != clientConfig.getDatabase()) {
      jedis.select(clientConfig.getDatabase());
    }
  }
  @Override
  public boolean validateObject(PooledObject<Jedis> pooledJedis) {
    final BinaryJedis jedis = pooledJedis.getObject();
    try {
      String host = jedisSocketFactory.getHost();
      int port = jedisSocketFactory.getPort();
      String connectionHost = jedis.getClient().getHost();
      int connectionPort = jedis.getClient().getPort();
      return host.equals(connectionHost)
          && port == connectionPort && jedis.isConnected()
          && jedis.ping().equals("PONG");
    } catch (final Exception e) {
      logger.error("Error while validating pooled Jedis object.", e);
      return false;
    }
  }
  @Override
  public void passivateObject(PooledObject<Jedis> pooledJedis) throws Exception {
    // TODO maybe should select db 0? Not sure right now.
  }
  @Override
  public void destroyObject(PooledObject<Jedis> pooledJedis) throws Exception {
    final BinaryJedis jedis = pooledJedis.getObject();
    if (jedis.isConnected()) {
      try {
        // need a proper test, probably with mock
        if (!jedis.isBroken()) {
          jedis.quit();
        }
      } catch (RuntimeException e) {
        logger.warn("Error while QUIT", e);
      }
      try {
        jedis.close();
      } catch (RuntimeException e) {
        logger.warn("Error while close", e);
      }
    }
  }
JedisFactory的activateObject判斷db是否一樣,不一樣則執(zhí)行select方法;validateObject方法則執(zhí)行ping;passivateObject方法為空操作;destroyObject方法會判斷是否broken,非broken執(zhí)行quit,最后執(zhí)行close方法

Evictor

org/apache/commons/pool2/impl/BaseGenericObjectPool.java

/**
     * The idle object evictor {@link TimerTask}.
     *
     * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
     */
    class Evictor implements Runnable {
        private ScheduledFuture<?> scheduledFuture;
        /**
         * Cancels the scheduled future.
         */
        void cancel() {
            scheduledFuture.cancel(false);
        }
        /**
         * Run pool maintenance.  Evict objects qualifying for eviction and then
         * ensure that the minimum number of idle instances are available.
         * Since the Timer that invokes Evictors is shared for all Pools but
         * pools may exist in different class loaders, the Evictor ensures that
         * any actions taken are under the class loader of the factory
         * associated with the pool.
         */
        @Override
        public void run() {
            final ClassLoader savedClassLoader =
                    Thread.currentThread().getContextClassLoader();
            try {
                if (factoryClassLoader != null) {
                    // Set the class loader for the factory
                    final ClassLoader cl = factoryClassLoader.get();
                    if (cl == null) {
                        // The pool has been dereferenced and the class loader
                        // GC'd. Cancel this timer so the pool can be GC'd as
                        // well.
                        cancel();
                        return;
                    }
                    Thread.currentThread().setContextClassLoader(cl);
                }
                // Evict from the pool
                try {
                    evict();
                } catch(final Exception e) {
                    swallowException(e);
                } catch(final OutOfMemoryError oome) {
                    // Log problem but give evictor thread a chance to continue
                    // in case error is recoverable
                    oome.printStackTrace(System.err);
                }
                // Re-create idle instances.
                try {
                    ensureMinIdle();
                } catch (final Exception e) {
                    swallowException(e);
                }
            } finally {
                // Restore the previous CCL
                Thread.currentThread().setContextClassLoader(savedClassLoader);
            }
        }
        /**
         * Sets the scheduled future.
         *
         * @param scheduledFuture the scheduled future.
         */
        void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) {
            this.scheduledFuture = scheduledFuture;
        }
    }
Evictor實(shí)現(xiàn)了Runnable方法,其run方法先執(zhí)行evict方法,后執(zhí)行ensureMinIdle方法

setTimeBetweenEvictionRuns

org/apache/commons/pool2/impl/BaseGenericObjectPool.java

/**
     * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
     * <ul>
     * <li>When positive, the idle object evictor thread starts.</li>
     * <li>When non-positive, no idle object evictor thread runs.</li>
     * </ul>
     *
     * @param timeBetweenEvictionRuns
     *            duration to sleep between evictor runs
     *
     * @see #getTimeBetweenEvictionRunsMillis
     * @since 2.10.0
     */
    public final void setTimeBetweenEvictionRuns(final Duration timeBetweenEvictionRuns) {
        this.durationBetweenEvictionRuns = PoolImplUtils.nonNull(timeBetweenEvictionRuns, BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS);
        startEvictor(this.durationBetweenEvictionRuns);
    }
setTimeBetweenEvictionRuns方法會給durationBetweenEvictionRuns賦值,同時(shí)執(zhí)行startEvictor方法

startEvictor

org/apache/commons/pool2/impl/BaseGenericObjectPool.java

/**
     * <p>Starts the evictor with the given delay. If there is an evictor
     * running when this method is called, it is stopped and replaced with a
     * new evictor with the specified delay.</p>
     *
     * <p>This method needs to be final, since it is called from a constructor.
     * See POOL-195.</p>
     *
     * @param delay time in milliseconds before start and between eviction runs
     */
    final void startEvictor(final Duration delay) {
        synchronized (evictionLock) {
            final boolean isPositiverDelay = PoolImplUtils.isPositive(delay);
            if (evictor == null) { // Starting evictor for the first time or after a cancel
                if (isPositiverDelay) { // Starting new evictor
                    evictor = new Evictor();
                    EvictionTimer.schedule(evictor, delay, delay);
                }
            } else if (isPositiverDelay) { // Stop or restart of existing evictor: Restart
                synchronized (EvictionTimer.class) { // Ensure no cancel can happen between cancel / schedule calls
                    EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, true);
                    evictor = null;
                    evictionIterator = null;
                    evictor = new Evictor();
                    EvictionTimer.schedule(evictor, delay, delay);
                }
            } else { // Stopping evictor
                EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, false);
            }
        }
    }
startEvictor方法會判斷delay是否是正數(shù),是的話,則執(zhí)行EvictionTimer.schedule(evictor, delay, delay),不是則執(zhí)行EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, false);對于evictor不為null的會先執(zhí)行cancel再執(zhí)行schedule

EvictionTimer

org/apache/commons/pool2/impl/EvictionTimer.java

/**
     * Adds the specified eviction task to the timer. Tasks that are added with
     * a call to this method *must* call {@link
     * #cancel(BaseGenericObjectPool.Evictor, Duration, boolean)}
     * to cancel the task to prevent memory and/or thread leaks in application
     * server environments.
     *
     * @param task      Task to be scheduled.
     * @param delay     Delay in milliseconds before task is executed.
     * @param period    Time in milliseconds between executions.
     */
    static synchronized void schedule(
            final BaseGenericObjectPool<?>.Evictor task, final Duration delay, final Duration period) {
        if (null == executor) {
            executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
            executor.setRemoveOnCancelPolicy(true);
            executor.scheduleAtFixedRate(new Reaper(), delay.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS);
        }
        final WeakReference<Runnable> ref = new WeakReference<>(task);
        final WeakRunner runner = new WeakRunner(ref);
        final ScheduledFuture<?> scheduledFuture = executor.scheduleWithFixedDelay(runner, delay.toMillis(),
                period.toMillis(), TimeUnit.MILLISECONDS);
        task.setScheduledFuture(scheduledFuture);
        taskMap.put(ref, runner);
    }
schedule方法使用的是ScheduledThreadPoolExecutor的scheduleWithFixedDelay方法來執(zhí)行evictor;而再executor為null時(shí)會創(chuàng)建ScheduledThreadPoolExecutor,同時(shí)觸發(fā)scheduleAtFixedRate來執(zhí)行Reaper

Reaper

org/apache/commons/pool2/impl/EvictionTimer.java

/**
     * Task that removes references to abandoned tasks and shuts
     * down the executor if there are no live tasks left.
     */
    private static class Reaper implements Runnable {
        @Override
        public void run() {
            synchronized (EvictionTimer.class) {
                for (final Entry<WeakReference<Runnable>, WeakRunner> entry : taskMap.entrySet()) {
                    if (entry.getKey().get() == null) {
                        executor.remove(entry.getValue());
                        taskMap.remove(entry.getKey());
                    }
                }
                if (taskMap.isEmpty() && executor != null) {
                    executor.shutdown();
                    executor.setCorePoolSize(0);
                    executor = null;
                }
            }
        }
    }
Reaper主要是遍歷taskMap,刪除被cancel掉的task

小結(jié)

jedis的testWhileIdle是依賴Evictor來進(jìn)行的,即Evictor它通過evictionPolicy.evict判斷是否需要evict,如果是則執(zhí)行evict邏輯,即destroy方法,否則走testWhileIdle的邏輯。testWhileIdle先執(zhí)行activateObject方法,再執(zhí)行validateObject,如果activateObject或者validateObject失敗則執(zhí)行destroy方法,最后如果validateObject成功則執(zhí)行passivateObject方法。

Evictor實(shí)現(xiàn)了Runnable方法,其run方法先執(zhí)行evict方法,后執(zhí)行ensureMinIdle方法;BaseGenericObjectPool的setTimeBetweenEvictionRuns方法會給durationBetweenEvictionRuns賦值,同時(shí)執(zhí)行startEvictor方法,即觸發(fā)執(zhí)行EvictionTimer.schedule(evictor, delay, delay),schedule方法使用的是ScheduledThreadPoolExecutor的scheduleWithFixedDelay方法來執(zhí)行evictor。

doc

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

相關(guān)文章

  • SpringBoot中@ConditionalOnProperty的使用及作用詳解

    SpringBoot中@ConditionalOnProperty的使用及作用詳解

    這篇文章主要介紹了SpringBoot中@ConditionalOnProperty的使用及作用詳解,@ConditionalOnProperty通過讀取本地配置文件中的值來判斷 某些 Bean 或者 配置類 是否加入spring 中,需要的朋友可以參考下
    2024-01-01
  • 使用AOP的@Around后無返回值的解決

    使用AOP的@Around后無返回值的解決

    這篇文章主要介紹了使用AOP的@Around后無返回值的解決,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java 如何利用緩沖流讀寫文件

    Java 如何利用緩沖流讀寫文件

    這篇文章主要介紹了Java 如何利用緩沖流讀寫文件的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java Properties簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    Java Properties簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    Java中有個(gè)比較重要的類Properties(Java.util.Properties),主要用于讀取Java的配置文件,各種語言都有自己所支持的配置文件,配置文件中很多變量是經(jīng)常改變的,這樣做也是為了方便用戶,讓用戶能夠脫離程序本身去修改相關(guān)的變量設(shè)置
    2017-05-05
  • Java中的List接口實(shí)現(xiàn)類LinkList和ArrayList詳解

    Java中的List接口實(shí)現(xiàn)類LinkList和ArrayList詳解

    這篇文章主要介紹了Java中的List接口實(shí)現(xiàn)類LinkList和ArrayList詳解,List接口繼承自Collection接口,是單列集合的一個(gè)重要分支,實(shí)現(xiàn)了List接口的對象稱為List集合,在List集合中允許出現(xiàn)重復(fù)的元素,所有的元素是以一種線性方式進(jìn)行存儲的,需要的朋友可以參考下
    2024-01-01
  • 詳解如何使用XML配置來定義和管理Spring Bean

    詳解如何使用XML配置來定義和管理Spring Bean

    XML 配置文件是 Spring 中傳統(tǒng)的 Bean 配置方式,通過定義 XML 元素來描述 Bean 及其依賴關(guān)系,在 Spring 框架中,Bean 是由 Spring IoC(控制反轉(zhuǎn))容器管理的對象,本文將詳細(xì)介紹如何使用 XML 配置來定義和管理 Spring Bean,需要的朋友可以參考下
    2024-06-06
  • Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)絡(luò)圖片顯示

    Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)絡(luò)圖片顯示

    這篇文章主要為大家詳細(xì)介紹了Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)絡(luò)圖片顯示的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • Java實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能的示例代碼

    Java實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)網(wǎng)絡(luò)資源的斷點(diǎn)續(xù)傳功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下
    2022-10-10
  • java設(shè)計(jì)模式--原型模式詳解

    java設(shè)計(jì)模式--原型模式詳解

    這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式之Prototype原型模式的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • SpringMVC如何自定義響應(yīng)的HTTP狀態(tài)碼

    SpringMVC如何自定義響應(yīng)的HTTP狀態(tài)碼

    這篇文章主要介紹了SpringMVC如何自定義響應(yīng)的HTTP狀態(tài)碼,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評論