001package jmri.util;
002
003import java.util.concurrent.*;
004
005/**
006 * @author Steve Young Copyright (C) 2024
007 */
008public class JmriThreadPoolExecutor extends ThreadPoolExecutor {
009
010    private final String threadName;
011
012    public JmriThreadPoolExecutor(int poolSize, String threadName) {
013        super(poolSize, poolSize, 1, TimeUnit.SECONDS,
014              new LinkedBlockingQueue<>(), new ShutDownThreadFactory(threadName));
015        this.threadName = threadName;
016        // Set a custom RejectedExecutionHandler to handle tasks that are rejected.
017        this.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor executor) ->
018            log.error("{} Task was rejected: {}", threadName, r));
019    }
020
021    @Override
022    protected void afterExecute(Runnable r, Throwable t) {
023        super.afterExecute(r, t);
024        if (t == null && r instanceof Future<?>) {
025            try {
026                Future<?> future = (Future<?>) r;
027                if (future.isDone() && !future.isCancelled()) {
028                    future.get(); // this will throw any exceptions encountered during execution
029                }
030            } catch (CancellationException ce) {
031                log.error("{} Task was cancelled: {}", threadName, r );
032            } catch (ExecutionException ee) {
033                log.error("{} Exception in task: {}", threadName, r, ee );
034            } catch (InterruptedException ie) {
035                // Restore interrupted state
036                Thread.currentThread().interrupt();
037            }
038        } else if (t != null) {
039            // Log the exception that occurred during execution
040            log.error("{} Exception in task execution: {}", threadName, r, t);
041        }
042
043    }
044
045    private static class ShutDownThreadFactory implements ThreadFactory {
046
047        private final String threadName;
048
049        private ShutDownThreadFactory( String threadName ){
050            super();
051            this.threadName = threadName;
052        }
053
054        @Override
055        public Thread newThread(Runnable r) {
056            return new Thread(r, threadName);
057        }
058    }
059
060    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(JmriThreadPoolExecutor.class);
061
062}