HikariPoolソース(IV)の状態のリソース

Javaのオタク|著者/   Kengran葉
これは、Javaのオタク 55元の記事の

1.この章の目的

リソース共有元の状態と同様の状態変化を理解する方法、デザインの参考のためにリソースをプールします。

2.HikariPoolリソースのコアクラスレビュー

次のようにHikariPool資源関連のクラスは次のとおりです。

クラス概要:

カテゴリ 責任
HikariPool リソースプール、入り口クライアントリソース操作。
ConcurrentBag GMとの契約ツール。
CopyOnWriteArrayListと PoolEntryあるストレージのためのリソースのリスト、。その特徴は、並行性を向上させるために、ロック、書き込みロックを、読んでいません。
プールエントリ リソースパッケージ、パッケージ・コネクション、このクラスのリソースレコードの状態。
接続 本当にリソース、データベース接続を適用したいです。

3.リソースのステータス

すなわち、PoolEntryの状態や、実際に二つの属性:

3.1状態

リソースを宣言する状態は以下のようにその状態が変化し、提供されています:

状態 ときに変更します
使用されていません 1.接続プールが初期化されている
プールに2リリースリソースバック
3.貸出リソースいないときに十分なリソース
使用中で 利用可能なリソースを貸します。
予約 1.リソースが最大のライフサイクル越え
2.資源プールのシャットダウンを
するときレトログラード時間3.Detect
4と呼ばれる、発信者の取り組み。
削除されました 1.接続プールの初期化、動的ストレッチ(落下時間)が
接続取得2.
3.特定のエラーが発生しました。

3.1.1 NOT INを使用します

説明状態リソースは、単に初期化またはリリースのリソースがリソースプールにバックアップ状態になるだろうされているリソースの割り当てを待って、使用されていません。

1.接続プールの初期化は、接続プールのリソースを初期化し、資源の最小数を達成、これらのリソースは、この状態で初期化されています。

2.资源使用完释放会池中时,资源状态会从In Use变成Not In Use。 3.出借资源,资源不足时,此时如果池中的资源数没有达到最大资源数,则会创建新的资源,新资源状态也是这个状态。

3.1.2 In Use

唯一的场景就是出借资源后,资源从Not In Use变成In Use。

3.1.3 Reserved

1.资源超过最大生命周期时是指:每一个资源实例可以设置最大生命周期,如果超过最大生命周期还没有使用(Not In Use)则会调整为Reserved状态,这个状态下资源不能被使用。

2.资源池shoudown时也会先将资源的状态从Not In Use修改为Reserved状态,避免再被出借出去。

3.Detect retrograde time时,是一个很特殊的场景,这是检查时钟同步时是否回拨了,这个场景我们一般不会考虑到,参考代码如下:

//HouseKeeper.java
            // Detect retrograde time, allowing +128ms as per NTP spec.
            if (plusMillis(now, 128) < plusMillis(previous, housekeepingPeriodMs)) {
               logger.warn("{} - Retrograde clock change detected (housekeeper delta={}), soft-evicting connections from pool.",
                           poolName, elapsedDisplayString(previous, now));
               previous = now;
               softEvictConnections();
               return;
            }
复制代码

资源什么时候超过最大生命周期,是通过一个延迟的线程任务来执行,如果线程执行了,资源还没有被使用,说明超过了最大生命周期。

4.允许调用者主动调用方法来设置这个状态,HikariPool中没有直接调用点。代码如下:

//HikariDataSource.java
   /**
    * Evict a connection from the pool.  If the connection has already been closed (returned to the pool)
    * this may result in a "soft" eviction; the connection will be evicted sometime in the future if it is
    * currently in use.  If the connection has not been closed, the eviction is immediate.
    *
    * @param connection the connection to evict from the pool
    */
   public void evictConnection(Connection connection)
   {
      HikariPool p;
      if (!isClosed() && (p = pool) != null && connection.getClass().getName().startsWith("com.zaxxer.hikari")) {
         p.evictConnection(connection);
      }
   }
复制代码

3.1.4 Removed

这个状态意味着资源从连接池中清除,数据库连接被真正关闭,资源被释放。

1.连接池初始化,动态伸缩时(降时),这是指资源数量超过最小连接数,并且部分连接的闲置时间也已经超过允许的闲置时间,那么就会释放这些连接,使得池中的资源数量降到最小连接数。

2.获取连接时,通常我们不可能在此时去释放连接,这里是因为当连接池shutdown时,有的连接可能被设置为evicted,这样的连接是不可用的,对这样的连接要释放掉,导致这个场景发生的原因这两个动作没有加锁,而不加锁的目的是为了提升性能,毕竟这种场景并不多见,大多数时候不会出现,也就在大多数情况下提升了性能。

3.发生特定异常时,这类异常都是直接导致数据库连接不可用的异常,因此会将数据库连接释放掉。

3.2 evict

资源的另外一个状态或者属性是evict标志,如果标志为true,就意味着资源不可用。其状态变化比较简单,默认为false。


这个标记最主要的作用是在获取资源时,如果资源的evict标志为true,则这个资源不可用,会接着获取下一个资源。

资源变为true的时机可参考state变为removed的时机,可以理解为就是资源不可用,将要清理并释放掉的时候。

从上面两个状态的变化来看,似乎用removed状态可以替代evict为true,但是在HikariPool中并没有这么做,一方面可能是因为从业务上讲两者的业务含义不同,另外一方面evict还用在异常处理中,对于异常的处理这里不再深入展开,有兴趣可以看下源码。

4. 总结

HikariPool使用了资源状态来控制资源是否可用,而不是通过一个可用资源池和一个已用资源池来控制资源可用,这么做的好处有:

  1. 控制粒度更小,更精确,不需要在池上加锁,只要在具体资源上加锁,符合并发编程优化的减小锁粒度原则
  2. 扩展更容易,如果通过不同的池来控制,那么增加新的状态,会导致要增加新的池来记录这些资源。

HikariPool使用了state和evict来控制资源的使用,实际设计时是否需要如此,要结合实际情况来看:

  1. 解耦的角度看,如果业务上是两个业务语义,并且不同语义有不同用途,那么就分开。
  2. 如果实际业务只需要一个state就够了,就没有必要一开始就拆分为两个,可遵循适用原则,等有需要时再扩展。

end.


<--感谢三连击,左边点赞和关注。


相关阅读:
HikariPool源码(一)初识
HikariPool源码(二)设计思想借鉴
HikariPool源码(三)资源池动态伸缩


Javaのオタクサイト: javageektour.com/

おすすめ

転載: juejin.im/post/5e8dd39b5188257397286a37