Bug Description
The executor service is created with Executors.newFixedThreadPool(10) which uses the default thread factory. This creates threads with generic names like "pool-1-thread-1" making it difficult to identify API server threads in thread dumps or monitoring tools.
Location
jplatform-rest-api/src/main/java/org/flossware/jplatform/rest/JdkHttpApiServer.java:136
Problematic Code
// Configure executor for handling requests
executor = Executors.newFixedThreadPool(10); // Default thread factory!
server.setExecutor(executor);
Impact
- Difficult debugging: Can't identify API threads in thread dumps
- Poor monitoring: Thread metrics not labeled properly
- Confusing profiling: Generic names in profiler output
- Thread leak detection: Hard to find which component leaked threads
- Production troubleshooting: Can't tell what threads are doing
Example
JdkHttpApiServer server = new JdkHttpApiServer(config, manager);
server.start();
// Thread dump shows:
"pool-1-thread-1" #15 prio=5 os_prio=0 tid=0x00007f1234567890 nid=0x1234 waiting
"pool-1-thread-2" #16 prio=5 os_prio=0 tid=0x00007f1234567891 nid=0x1235 waiting
"pool-1-thread-3" #17 prio=5 os_prio=0 tid=0x00007f1234567892 nid=0x1236 waiting
// What are these threads for?
// - API server?
// - Database connection pool?
// - Background job executor?
// - Message queue consumer?
// Can't tell without stack trace!
// In production with multiple thread pools:
"pool-1-thread-1" ... "pool-1-thread-10" <- API server
"pool-2-thread-1" ... "pool-2-thread-20" <- Database pool
"pool-3-thread-1" ... "pool-3-thread-5" <- Job executor
"pool-4-thread-1" ... "pool-4-thread-50" <- Message consumer
// All generic names, impossible to distinguish
// When thread leak occurs:
// Thread count keeps growing
// Monitoring shows "pool-N-thread-X" increasing
// Which component is leaking? Can't tell
// Must attach debugger and inspect each thread
Proposed Fix
Use a custom thread factory with descriptive names:
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
// Configure executor for handling requests with custom thread factory
executor = Executors.newFixedThreadPool(10, new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "jplatform-api-server-" + threadNumber.getAndIncrement());
thread.setDaemon(false); // Explicit non-daemon
thread.setPriority(Thread.NORM_PRIORITY);
thread.setUncaughtExceptionHandler((t, e) -> {
logger.error("Uncaught exception in thread {}", t.getName(), e);
});
return thread;
}
});
server.setExecutor(executor);
// Now thread dump shows:
"jplatform-api-server-1" #15 prio=5 os_prio=0 tid=0x00007f1234567890 nid=0x1234 waiting
"jplatform-api-server-2" #16 prio=5 os_prio=0 tid=0x00007f1234567891 nid=0x1235 waiting
"jplatform-api-server-3" #17 prio=5 os_prio=0 tid=0x00007f1234567892 nid=0x1236 waiting
// Much clearer!
Or use Guava's ThreadFactoryBuilder:
import com.google.common.util.concurrent.ThreadFactoryBuilder;
executor = Executors.newFixedThreadPool(10,
new ThreadFactoryBuilder()
.setNameFormat("jplatform-api-server-%d")
.setDaemon(false)
.setPriority(Thread.NORM_PRIORITY)
.setUncaughtExceptionHandler((t, e) ->
logger.error("Uncaught exception in {}", t.getName(), e))
.build()
);
server.setExecutor(executor);
Or create reusable factory class:
private static class NamedThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final boolean daemon;
NamedThreadFactory(String namePrefix, boolean daemon) {
this.namePrefix = namePrefix;
this.daemon = daemon;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, namePrefix + threadNumber.getAndIncrement());
thread.setDaemon(daemon);
thread.setUncaughtExceptionHandler((t, e) -> {
LoggerFactory.getLogger(t.getName()).error("Uncaught exception", e);
});
return thread;
}
}
// Usage:
executor = Executors.newFixedThreadPool(10,
new NamedThreadFactory("jplatform-api-server-", false));
Bug Description
The executor service is created with
Executors.newFixedThreadPool(10)which uses the default thread factory. This creates threads with generic names like "pool-1-thread-1" making it difficult to identify API server threads in thread dumps or monitoring tools.Location
jplatform-rest-api/src/main/java/org/flossware/jplatform/rest/JdkHttpApiServer.java:136Problematic Code
Impact
Example
Proposed Fix
Use a custom thread factory with descriptive names:
Or use Guava's ThreadFactoryBuilder:
Or create reusable factory class: