11package dev .imprex .orebfuscator .util .concurrent ;
22
3+ import dev .imprex .orebfuscator .config .yaml .ConfigurationSection ;
4+ import java .util .Arrays ;
5+ import java .util .List ;
36import java .util .Objects ;
7+ import java .util .concurrent .BlockingQueue ;
48import java .util .concurrent .Executor ;
59import java .util .concurrent .ExecutorService ;
610import java .util .concurrent .Executors ;
11+ import java .util .concurrent .LinkedBlockingQueue ;
712import java .util .concurrent .ScheduledExecutorService ;
813import java .util .concurrent .ScheduledFuture ;
14+ import java .util .concurrent .ScheduledThreadPoolExecutor ;
15+ import java .util .concurrent .ThreadPoolExecutor ;
916import java .util .concurrent .TimeUnit ;
1017import java .util .concurrent .atomic .LongAdder ;
18+ import java .util .stream .Collectors ;
1119import org .jspecify .annotations .NullMarked ;
1220import dev .imprex .orebfuscator .interop .OrebfuscatorCore ;
1321import dev .imprex .orebfuscator .statistics .OrebfuscatorStatistics ;
1422
1523@ NullMarked
1624public class OrebfuscatorExecutor implements Executor {
1725
18- private final ScheduledExecutorService scheduledExecutorService = Executors
19- . newSingleThreadScheduledExecutor ( r -> new Thread (OrebfuscatorCore .THREAD_GROUP , r , "orebfuscator-scheduler" ));
26+ private final ScheduledThreadPoolExecutor scheduledExecutorService = new ScheduledThreadPoolExecutor (
27+ 1 , r -> new Thread (OrebfuscatorCore .THREAD_GROUP , r , "orebfuscator-scheduler" ));
2028
2129 private final int poolSize ;
22- private final ExecutorService executorService ;
30+ private final ThreadPoolExecutor executorService ;
2331
2432 private final LongAdder run = new LongAdder ();
2533 private long updateTime = System .nanoTime ();
@@ -30,7 +38,11 @@ public OrebfuscatorExecutor(OrebfuscatorCore orebfuscator) {
3038 this .statistics = orebfuscator .statistics ();
3139
3240 this .poolSize = orebfuscator .config ().advanced ().threads ();
33- this .executorService = Executors .newFixedThreadPool (this .poolSize , OrebfuscatorThread ::new );
41+ this .executorService = new ThreadPoolExecutor (
42+ this .poolSize , this .poolSize ,
43+ 0L , TimeUnit .MILLISECONDS ,
44+ new LinkedBlockingQueue <>(),
45+ OrebfuscatorThread ::new );
3446
3547 this .scheduledExecutorService .scheduleAtFixedRate (this ::updateStatistics , 1L , 1L , TimeUnit .SECONDS );
3648 }
@@ -65,6 +77,79 @@ public void shutdown() {
6577 this .executorService .shutdownNow ();
6678 }
6779
80+ public void dump (ConfigurationSection section ) {
81+ dumpExecutor (section .createSection ("scheduler" ), this .scheduledExecutorService );
82+ dumpExecutor (section .createSection ("core" ), this .executorService );
83+
84+ ConfigurationSection threads = section .createSection ("threads" );
85+
86+ for (var entry : Thread .getAllStackTraces ().entrySet ()) {
87+ Thread thread = entry .getKey ();
88+
89+ if (!(thread instanceof OrebfuscatorThread )) {
90+ continue ;
91+ }
92+
93+ StackTraceElement [] stackTrace = entry .getValue ();
94+
95+ ConfigurationSection threadSection =
96+ threads .createSection ("thread-" + thread .getId ());
97+
98+ threadSection .set ("name" , thread .getName ());
99+ threadSection .set ("id" , thread .getId ());
100+ threadSection .set ("state" , thread .getState ().name ());
101+ threadSection .set ("alive" , thread .isAlive ());
102+ threadSection .set ("daemon" , thread .isDaemon ());
103+ threadSection .set ("priority" , thread .getPriority ());
104+ threadSection .set ("stack" , formatStackTrace (stackTrace ));
105+ }
106+ }
107+
108+ private static void dumpExecutor (ConfigurationSection section , ThreadPoolExecutor executor ) {
109+ section .set ("shutdown" , executor .isShutdown ());
110+ section .set ("terminating" , executor .isTerminating ());
111+ section .set ("terminated" , executor .isTerminated ());
112+
113+ section .set ("pool.size" , executor .getPoolSize ());
114+ section .set ("pool.coreSize" , executor .getCorePoolSize ());
115+ section .set ("pool.maxSize" , executor .getMaximumPoolSize ());
116+ section .set ("pool.largestSize" , executor .getLargestPoolSize ());
117+ section .set ("pool.active" , executor .getActiveCount ());
118+
119+ long taskCount = executor .getTaskCount ();
120+ long completedTaskCount = executor .getCompletedTaskCount ();
121+
122+ section .set ("tasks.total" , taskCount );
123+ section .set ("tasks.completed" , completedTaskCount );
124+ section .set ("tasks.pending" , Math .max (0 , taskCount - completedTaskCount ));
125+
126+ BlockingQueue <Runnable > queue = executor .getQueue ();
127+ section .set ("queue.type" , queue .getClass ().getName ());
128+ section .set ("queue.size" , queue .size ());
129+ section .set ("queue.remainingCapacity" , queue .remainingCapacity ());
130+
131+ section .set ("keepAliveMillis" , executor .getKeepAliveTime (TimeUnit .MILLISECONDS ));
132+ section .set ("allowsCoreThreadTimeOut" , executor .allowsCoreThreadTimeOut ());
133+
134+ section .set ("threadFactory" , executor .getThreadFactory ().getClass ().getName ());
135+ section .set ("rejectedExecutionHandler" , executor .getRejectedExecutionHandler ().getClass ().getName ());
136+
137+ if (executor instanceof ScheduledThreadPoolExecutor scheduled ) {
138+ section .set ("scheduled.continueExistingPeriodicTasksAfterShutdown" ,
139+ scheduled .getContinueExistingPeriodicTasksAfterShutdownPolicy ());
140+ section .set ("scheduled.executeExistingDelayedTasksAfterShutdown" ,
141+ scheduled .getExecuteExistingDelayedTasksAfterShutdownPolicy ());
142+ section .set ("scheduled.removeOnCancel" ,
143+ scheduled .getRemoveOnCancelPolicy ());
144+ }
145+ }
146+
147+ private static List <String > formatStackTrace (StackTraceElement [] stackTrace ) {
148+ return Arrays .stream (stackTrace )
149+ .map (element -> "at " + element )
150+ .collect (Collectors .toList ());
151+ }
152+
68153 private void updateStatistics () {
69154 long time = System .nanoTime ();
70155 try {
0 commit comments