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}