class LtThreadPoolExecutor extends ThreadPoolExecutor {

  private static final Gauge maxQueueSize = Gauge.build("languagetool_threadpool_max_queue_size", "Queue capacity by threadpool")
    .labelNames("pool").register();
  private static final Gauge queueSize = Gauge.build("languagetool_threadpool_queue_size", "Queue size by threadpool")
    .labelNames("pool").register();
  private static final Gauge largestPoolSize = Gauge.build("languagetool_threadpool_largest_queue_size", "The largest number of threads that have ever simultaneously been in the pool")
    .labelNames("pool").register();

  @Getter
  private final String name;

  LtThreadPoolExecutor(String name, int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory, @NotNull RejectedExecutionHandler handler) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    this.name = name;
    maxQueueSize.labels(name).set(workQueue.remainingCapacity());
  }

  {
    Timer timer = new Timer("LtThreadPoolExecutorMonitor", true);
    TimerTask timedAction = new TimerTask() {
      @Override
      public void run() {
        queueSize.labels(name).set(getQueue().size());
        largestPoolSize.labels(name).set(getLargestPoolSize());
        log.trace("{} queueSize: {}", name, queueSize.labels(name).get());
        log.trace("{} largestPoolSize: {}", name, largestPoolSize.labels(name).get());
      }
    };
    timer.scheduleAtFixedRate(timedAction, 0, 1000);
  }

  @Override
  public void execute(@NotNull Runnable command) {
    super.execute(command);
  }

  @Override
  public boolean remove(Runnable task) {
    return super.remove(task);
  }

  @Override
  protected void afterExecute(Runnable r, Throwable t) {<FILL_FUNCTION_BODY>}

  @Override
  protected void beforeExecute(Thread t, Runnable r) {
    super.beforeExecute(t, r);
  }
}

    super.afterExecute(r, t);

    // inherited from removed StoppingThreadPoolExecutor in org.languagetool.server.Server
    if (t != null && t instanceof OutOfMemoryError) {
      // we prefer to stop instead of being in an unstable state:
      //noinspection CallToPrintStackTrace
      t.printStackTrace();
      System.exit(1);
    }
  
<methods>public void <init>(int, int, long, java.util.concurrent.TimeUnit, BlockingQueue<java.lang.Runnable>) ,public void <init>(int, int, long, java.util.concurrent.TimeUnit, BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory) ,public void <init>(int, int, long, java.util.concurrent.TimeUnit, BlockingQueue<java.lang.Runnable>, java.util.concurrent.RejectedExecutionHandler) ,public void <init>(int, int, long, java.util.concurrent.TimeUnit, BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler) ,public void allowCoreThreadTimeOut(boolean) ,public boolean allowsCoreThreadTimeOut() ,public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException,public void execute(java.lang.Runnable) ,public int getActiveCount() ,public long getCompletedTaskCount() ,public int getCorePoolSize() ,public long getKeepAliveTime(java.util.concurrent.TimeUnit) ,public int getLargestPoolSize() ,public int getMaximumPoolSize() ,public int getPoolSize() ,public BlockingQueue<java.lang.Runnable> getQueue() ,public java.util.concurrent.RejectedExecutionHandler getRejectedExecutionHandler() ,public long getTaskCount() ,public java.util.concurrent.ThreadFactory getThreadFactory() ,public boolean isShutdown() ,public boolean isTerminated() ,public boolean isTerminating() ,public int prestartAllCoreThreads() ,public boolean prestartCoreThread() ,public void purge() ,public boolean remove(java.lang.Runnable) ,public void setCorePoolSize(int) ,public void setKeepAliveTime(long, java.util.concurrent.TimeUnit) ,public void setMaximumPoolSize(int) ,public void setRejectedExecutionHandler(java.util.concurrent.RejectedExecutionHandler) ,public void setThreadFactory(java.util.concurrent.ThreadFactory) ,public void shutdown() ,public List<java.lang.Runnable> shutdownNow() ,public java.lang.String toString() <variables>private static final int COUNT_BITS,private static final int COUNT_MASK,private static final boolean ONLY_ONE,private static final int RUNNING,private static final int SHUTDOWN,private static final int STOP,private static final int TERMINATED,private static final int TIDYING,private volatile boolean allowCoreThreadTimeOut,private long completedTaskCount,private volatile int corePoolSize,private final java.util.concurrent.atomic.AtomicInteger ctl,private static final java.util.concurrent.RejectedExecutionHandler defaultHandler,private volatile java.util.concurrent.RejectedExecutionHandler handler,private volatile long keepAliveTime,private int largestPoolSize,private final java.util.concurrent.locks.ReentrantLock mainLock,private volatile int maximumPoolSize,private static final java.lang.RuntimePermission shutdownPerm,private final java.util.concurrent.locks.Condition termination,private volatile java.util.concurrent.ThreadFactory threadFactory,private final BlockingQueue<java.lang.Runnable> workQueue,private final HashSet<java.util.concurrent.ThreadPoolExecutor.Worker> workers