聊聊hikari連接池的isAllowPoolSuspension

本文主要研究一下hikari連接池的isAllowPoolSuspension屬性

實(shí)例代碼

    @Test
    public void testPoolSuspend() throws SQLException {
        Connection conn = dataSource.getConnection();
        System.out.println("begin to suspend pool");
        ((HikariDataSource)dataSource).suspendPool();
        Connection conn2 = dataSource.getConnection();
        System.out.println("finish");
    }

suspend

begin to suspend pool

java.lang.IllegalStateException: HikariPool-1 - is not suspendable

    at com.zaxxer.hikari.pool.HikariPool.suspendPool(HikariPool.java:372)
    at com.zaxxer.hikari.HikariDataSource.suspendPool(HikariDataSource.java:326)
    at com.example.demo.HikariDemoApplicationTests.testPoolSuspend(HikariDemoApplicationTests.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

當(dāng)沒有設(shè)置的allow-pool-suspension=true時(shí)候精置,拋出java.lang.IllegalStateException: HikariPool-1 - is not suspendable

allow-pool-suspension=true

HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java

   /**
    * Construct a HikariPool with the specified configuration.
    *
    * @param config a HikariConfig instance
    */
   public HikariPool(final HikariConfig config)
   {
      super(config);

      this.connectionBag = new ConcurrentBag<>(this);
      this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK;

      this.houseKeepingExecutorService = initializeHouseKeepingExecutorService();

      checkFailFast();

      if (config.getMetricsTrackerFactory() != null) {
         setMetricsTrackerFactory(config.getMetricsTrackerFactory());
      }
      else {
         setMetricRegistry(config.getMetricRegistry());
      }

      setHealthCheckRegistry(config.getHealthCheckRegistry());

      registerMBeans(this);

      ThreadFactory threadFactory = config.getThreadFactory();

      LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(config.getMaximumPoolSize());
      this.addConnectionQueue = unmodifiableCollection(addConnectionQueue);
      this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardPolicy());
      this.closeConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());

      this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService);

      this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, HOUSEKEEPING_PERIOD_MS, MILLISECONDS);
   }

如果isAllowPoolSuspension為ture,則suspendResumeLock是一個(gè)真實(shí)的SuspendResumeLock阴汇,否則是SuspendResumeLock.FAUX_LOCK

SuspendResumeLock

/**
 * This class implements a lock that can be used to suspend and resume the pool.  It
 * also provides a faux implementation that is used when the feature is disabled that
 * hopefully gets fully "optimized away" by the JIT.
 *
 * @author Brett Wooldridge
 */
public class SuspendResumeLock
{
   public static final SuspendResumeLock FAUX_LOCK = new SuspendResumeLock(false) {
      @Override
      public void acquire() {}

      @Override
      public void release() {}
      
      @Override
      public void suspend() {}

      @Override
      public void resume() {}
   };

   private static final int MAX_PERMITS = 10000;
   private final Semaphore acquisitionSemaphore;

   /**
    * Default constructor
    */
   public SuspendResumeLock()
   {
      this(true);
   }

   private SuspendResumeLock(final boolean createSemaphore)
   {
      acquisitionSemaphore = (createSemaphore ? new Semaphore(MAX_PERMITS, true) : null);
   }

   public void acquire()
   {
      acquisitionSemaphore.acquireUninterruptibly();
   }

   public void release()
   {
      acquisitionSemaphore.release();
   }

   public void suspend()
   {
      acquisitionSemaphore.acquireUninterruptibly(MAX_PERMITS);
   }

   public void resume()
   {
      acquisitionSemaphore.release(MAX_PERMITS);
   }
}

FAUX_LOCK是一個(gè)空方法,false表示不創(chuàng)建信號(hào)量

suspend方法一次性消耗了MAX_PERMITS信號(hào)量碗脊,這個(gè)方法被調(diào)用之后弱睦,之后getConnection方法都獲取不到連接,永遠(yuǎn)阻塞在suspendResumeLock.acquire();

resume方法一次性釋放MAX_PERMITS信號(hào)量

HikariPool.getConnection

HikariCP-2.7.6-sources.jar!/com/zaxxer/hikari/pool/HikariPool.java

   /**
    * Get a connection from the pool, or timeout after connectionTimeout milliseconds.
    *
    * @return a java.sql.Connection instance
    * @throws SQLException thrown if a timeout occurs trying to obtain a connection
    */
   public Connection getConnection() throws SQLException
   {
      return getConnection(connectionTimeout);
   }

   /**
    * Get a connection from the pool, or timeout after the specified number of milliseconds.
    *
    * @param hardTimeout the maximum time to wait for a connection from the pool
    * @return a java.sql.Connection instance
    * @throws SQLException thrown if a timeout occurs trying to obtain a connection
    */
   public Connection getConnection(final long hardTimeout) throws SQLException
   {
      suspendResumeLock.acquire();
      final long startTime = currentTime();

      try {
         long timeout = hardTimeout;
         do {
            PoolEntry poolEntry = connectionBag.borrow(timeout, MILLISECONDS);
            if (poolEntry == null) {
               break; // We timed out... break and throw exception
            }

            final long now = currentTime();
            if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) {
               closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE);
               timeout = hardTimeout - elapsedMillis(startTime);
            }
            else {
               metricsTracker.recordBorrowStats(poolEntry, startTime);
               return poolEntry.createProxyConnection(leakTaskFactory.schedule(poolEntry), now);
            }
         } while (timeout > 0L);

         metricsTracker.recordBorrowTimeoutStats(startTime);
         throw createTimeoutException(startTime);
      }
      catch (InterruptedException e) {
         Thread.currentThread().interrupt();
         throw new SQLException(poolName + " - Interrupted during connection acquisition", e);
      }
      finally {
         suspendResumeLock.release();
      }
   }

可以看到getConnection是先獲取信號(hào)量赫编,最后不管獲取成功還是超時(shí)咱台,finally里頭去釋放這個(gè)信號(hào)量
這里的hardTimeout就是從連接池借用connection的超時(shí)時(shí)間

小結(jié)

isAllowPoolSuspension用來標(biāo)記釋放允許暫停連接池络拌,一旦被暫停,所有的getConnection方法都會(huì)被阻塞回溺〈好常可能的用處就是用來實(shí)現(xiàn)chaosmonkey混萝,模擬數(shù)據(jù)庫連接故障。作者在github上的解釋是可以用來做些配置修改:暫停連接池萍恕,修改連接池配置或dns配置逸嘀,soft-evit既有連接,然后恢復(fù)連接池允粤。

doc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厘熟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子维哈,更是在濱河造成了極大的恐慌,老刑警劉巖登澜,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阔挠,死亡現(xiàn)場離奇詭異,居然都是意外死亡脑蠕,警方通過查閱死者的電腦和手機(jī)购撼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谴仙,“玉大人迂求,你說我怎么就攤上這事』味澹” “怎么了揩局?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掀虎。 經(jīng)常有香客問我凌盯,道長,這世上最難降的妖魔是什么烹玉? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任驰怎,我火速辦了婚禮,結(jié)果婚禮上二打,老公的妹妹穿的比我還像新娘县忌。我一直安慰自己,他們只是感情好继效,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布症杏。 她就那樣靜靜地躺著,像睡著了一般莲趣。 火紅的嫁衣襯著肌膚如雪鸳慈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天喧伞,我揣著相機(jī)與錄音走芋,去河邊找鬼绩郎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翁逞,可吹牛的內(nèi)容都是我干的肋杖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼挖函,長吁一口氣:“原來是場噩夢啊……” “哼状植!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怨喘,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤津畸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后必怜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肉拓,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年梳庆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暖途。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膏执,死狀恐怖驻售,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情更米,我是刑警寧澤欺栗,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站壳快,受9級(jí)特大地震影響纸巷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜眶痰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一瘤旨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竖伯,春花似錦存哲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至打厘,卻和暖如春修肠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背户盯。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工嵌施, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饲化,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓吗伤,卻偏偏與公主長得像吃靠,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子足淆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法巢块,類相關(guān)的語法,內(nèi)部類的語法巧号,繼承相關(guān)的語法族奢,異常的語法,線程的語...
    子非魚_t_閱讀 31,639評(píng)論 18 399
  • 本文包括傳統(tǒng)JDBC的缺點(diǎn)連接池原理自定義連接池開源數(shù)據(jù)庫連接池DBCP連接池C3P0連接池Tomcat內(nèi)置連接池...
    廖少少閱讀 16,750評(píng)論 0 37
  • 前言 數(shù)據(jù)庫連接池在Java數(shù)據(jù)庫相關(guān)中間件產(chǎn)品群中丹鸿,應(yīng)該算是底層最基礎(chǔ)的一類產(chǎn)品歹鱼,作為企業(yè)應(yīng)用開發(fā)必不可少的組件...
    許da廣閱讀 7,175評(píng)論 2 27
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx?那么一定聽過它的“同行”Apache吧卜高!Ngi...
    JokerW閱讀 32,688評(píng)論 24 1,002
  • 做微商以來掺涛,總會(huì)時(shí)不時(shí)有人問我,有沒有賺到錢疤劢薪缆?賺了多少啦? 我會(huì)說伞广,還好拣帽,還好。 和什么群體接觸嚼锄,你就會(huì)慢慢成為...
    米修_b10e閱讀 345評(píng)論 0 0