77import java .sql .*;
88import java .util .*;
99import java .util .concurrent .ExecutorService ;
10- import java .util .concurrent .Executors ;
10+ import java .util .concurrent .RejectedExecutionException ;
1111import java .util .concurrent .TimeUnit ;
1212import java .util .concurrent .atomic .AtomicBoolean ;
1313import java .util .concurrent .atomic .AtomicInteger ;
@@ -30,7 +30,6 @@ final class ConnectionPool implements DataSourcePool {
3030
3131 private static final String APPLICATION_NAME = "ApplicationName" ;
3232 private final ReentrantLock heartbeatLock = new ReentrantLock (false );
33- private final ReentrantLock executorLock = new ReentrantLock (false );
3433 private final ReentrantLock notifyLock = new ReentrantLock (false );
3534 /**
3635 * The name given to this dataSource.
@@ -85,7 +84,7 @@ final class ConnectionPool implements DataSourcePool {
8584 private final PooledConnectionQueue queue ;
8685 private Timer heartBeatTimer ;
8786 private int heartbeatPoolExhaustedCount ;
88- private ExecutorService executor ;
87+ private final ExecutorService executor ;
8988
9089 /**
9190 * Used to find and close() leaked connections. Leaked connections are
@@ -140,6 +139,7 @@ final class ConnectionPool implements DataSourcePool {
140139 init ();
141140 }
142141 this .nextTrimTime = System .currentTimeMillis () + trimPoolFreqMillis ;
142+ this .executor = ExecutorFactory .newExecutor ();
143143 }
144144
145145 private void init () {
@@ -195,7 +195,6 @@ private void tryEnsureMinimumConnections() {
195195 private void initialiseConnections () throws SQLException {
196196 long start = System .currentTimeMillis ();
197197 dataSourceUp .set (true );
198- startExecutor ();
199198 if (failOnStart ) {
200199 queue .ensureMinimumConnections ();
201200 } else {
@@ -334,7 +333,6 @@ private void notifyUp() {
334333 // check such that we only notify once
335334 if (!dataSourceUp .get ()) {
336335 dataSourceUp .set (true );
337- startExecutor ();
338336 startHeartBeatIfStopped ();
339337 dataSourceDownReason = null ;
340338 Log .error ("RESOLVED FATAL: DataSource [" + name + "] is back up!" );
@@ -657,11 +655,13 @@ public void offline() {
657655 shutdownPool (false , false );
658656 }
659657
660- private void shutdownPool (boolean closeBusyConnections , boolean fromHook ) {
658+ private void shutdownPool (boolean fullShutdown , boolean fromHook ) {
661659 stopHeartBeatIfRunning ();
662- PoolStatus status = queue .shutdown (closeBusyConnections );
660+ PoolStatus status = queue .shutdown (fullShutdown );
663661 dataSourceUp .set (false );
664- stopExecutor ();
662+ if (fullShutdown ) {
663+ shutdownExecutor ();
664+ }
665665 if (fromHook ) {
666666 Log .info ("DataSource [{0}] shutdown on JVM exit {1} psc[hit:{2} miss:{3} put:{4} rem:{5}]" , name , status , pscHit , pscMiss , pscPut , pscRem );
667667 } else {
@@ -751,51 +751,31 @@ public String toString() {
751751 * Closes the connection in the background as it may be slow or block.
752752 */
753753 void closeConnectionFullyAsync (PooledConnection pc , boolean logErrors ) {
754- executorLock .lock ();
755- try {
756- if (executor != null ) {
754+ if (!executor .isShutdown ()) {
755+ try {
757756 executor .submit (new AsyncCloser (pc , logErrors ));
758757 return ;
758+ } catch (RejectedExecutionException e ) {
759+ Log .trace ("DataSource [{0}] closing connection synchronously" , name );
759760 }
760- } finally {
761- executorLock .unlock ();
762761 }
763762 // it is possible that we receive runnables after shutdown.
764763 // in this case, we will execute them immediately (outside lock)
765764 pc .doCloseConnection (logErrors );
766765 }
767766
768- private void startExecutor () {
769- executorLock . lock ();
767+ private void shutdownExecutor () {
768+ executor . shutdown ();
770769 try {
771- if (executor == null ) {
772- executor = ExecutorFactory . newExecutor ( );
770+ if (! executor . awaitTermination ( 5 , TimeUnit . SECONDS ) ) {
771+ Log . warn ( "DataSource [{0}] on shutdown, timeout waiting for connections to close" , name );
773772 }
774- } finally {
775- executorLock . unlock ( );
773+ } catch ( InterruptedException ie ) {
774+ Log . warn ( "DataSource [{0}] on shutdown, interrupted closing connections" , name , ie );
776775 }
777- }
778-
779- private void stopExecutor () {
780- executorLock .lock ();
781- try {
782- if (executor != null ) {
783- executor .shutdown ();
784- try {
785- if (!executor .awaitTermination (5 , TimeUnit .SECONDS )) {
786- Log .warn ("DataSource [{0}] timeout waiting for connections to close" , name );
787- }
788- } catch (InterruptedException ie ) {
789- Log .warn ("DataSource [{0}] could not terminate executor." , name , ie );
790- }
791- final var pendingTasks = executor .shutdownNow ();
792- if (!pendingTasks .isEmpty ()) {
793- Log .warn ("DataSource [{0}] {1} pending connections were not closed" , name , pendingTasks .size ());
794- }
795- executor = null ;
796- }
797- } finally {
798- executorLock .unlock ();
776+ final var pendingTasks = executor .shutdownNow ();
777+ if (!pendingTasks .isEmpty ()) {
778+ Log .warn ("DataSource [{0}] on shutdown, {1} pending connections were not closed" , name , pendingTasks .size ());
799779 }
800780 }
801781
0 commit comments