private ExecutorService createCustomExecutorService(int poolSize, final String method) {
    int coreSize = Runtime.getRuntime().availableProcessors();
    if (poolSize < coreSize) {
      coreSize = poolSize;
    }
    ThreadFactory tf =
        new ThreadFactory() {
          public Thread newThread(Runnable r) {
            Thread t =
                new Thread(r, "thread created at ShardSqlSessionTemplate method [" + method + "]");
            t.setDaemon(true);
            return t;
          }
        };
    BlockingQueue<Runnable> queueToUse = new LinkedBlockingQueue<Runnable>();
    final ThreadPoolExecutor executor =
        new ThreadPoolExecutor(
            coreSize,
            poolSize,
            60,
            TimeUnit.SECONDS,
            queueToUse,
            tf,
            new ThreadPoolExecutor.CallerRunsPolicy());

    return executor;
  }
  private ExecutorService createExecutorForSpecificDataSource(ShardDataSourceSpec dataSourceSpec) {
    final String identity = dataSourceSpec.getIdentity();
    final ExecutorService executor =
        createCustomExecutorService(
            dataSourceSpec.getPoolSize(),
            "createExecutorForSpecificDataSource-" + identity + " data source");
    // 1. register executor for disposing explicitly
    internalExecutorServiceRegistry.add(executor);
    // 2. dispose executor implicitly
    Runtime.getRuntime()
        .addShutdownHook(
            new Thread() {
              @Override
              public void run() {
                if (executor == null) {
                  return;
                }

                try {
                  executor.shutdown();
                  executor.awaitTermination(5, TimeUnit.MINUTES);
                } catch (InterruptedException e) {
                  logger.warn("interrupted when shuting down the query executor:\n{}", e);
                }
              }
            });
    return executor;
  }