-1

Can Jetty Server be configured not to pool threads, but to create/terminate a Thread every time? I at first thought to create a simple ThreadPool class, but it didn't look like...

We're aware that it's not very good for performance, and we are accepting it.

Dai MIKURUBE
  • 125
  • 1
  • 1
  • 13
  • What did you try? have some code or configuration? – LMC Sep 02 '21 at 01:49
  • I would try [](https://www.eclipse.org/jetty/documentation/jetty-11/operations-guide/index.html#og-modules-properties) – LMC Sep 02 '21 at 01:56
  • I just now tried the following, and going to look at how it works... final ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 200, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); executor.allowCoreThreadTimeOut(true); final ExecutorThreadPool threadPool = new ExecutorThreadPool(executor); final Server jettyServer = new Server(threadPool); – Dai MIKURUBE Sep 02 '21 at 02:35
  • The Jetty `ThreadPool` class is based on the `java.util.concurrent.Executor` which implies a proper threadpool along with proper join logic. Why do you want to do this? I ask, as there is perhaps a different way to accomplish your end goals. – Joakim Erdfelt Sep 02 '21 at 03:31
  • A no-pooling thread executor will actually consume more memory and increase your GC activity. We tried this with an experimental Jetty 11 branch to utilize JDK 17 loom threads more, the experience was worse in every way than a traditional threadpool. – Joakim Erdfelt Sep 02 '21 at 03:34
  • It's to kill `ThreadLocal` completely so that we can eliminate class loader leaks by some third-party libraries using `ThreadLocal` internally, which is out of our control. – Dai MIKURUBE Sep 02 '21 at 03:57
  • Yeah, we know about more memory and more GC, and they are acceptable. – Dai MIKURUBE Sep 02 '21 at 03:58
  • That server is not a very common web server, but an internal special one which receives just ~5 requests in an hour, and one request would trigger a heavy task (~60 secs) under a custom class loader. – Dai MIKURUBE Sep 02 '21 at 04:05
  • In terms of that, it's still okay with threads pooled, but we need those all threads are sometime cleaned up. – Dai MIKURUBE Sep 02 '21 at 04:10
  • Might want to read up on https://stackoverflow.com/questions/3869026/how-to-clean-up-threadlocals – Joakim Erdfelt Sep 02 '21 at 14:32
  • Thanks. Yeah, I've read that kind of topics, but found that there is only a way with reflection to clean up `ThreadLocal`s "out of our control" -- which are by other libraries. (In our case, JRuby is there.) – Dai MIKURUBE Sep 03 '21 at 01:32

1 Answers1

1

Reminder: Jetty is a 100% async server, there is absolutely NO relationship of 1 thread per 1 request. It is common for a single request to use 1..n threads per request. The number of threads per request is dictated on the technology choices you make (Protocol choices, API choices, Servlet choices, 3rd party library choices, etc). Example: you will use more threads when using things like Servlet Async Processing, Servlet Async I/O, HTTP/2, etc ...

This would be the minimum "no pooling thread pool" (a horrid concept that will actually consume more memory and increase your GC utilization by several orders of magnitude).

This thread pool implementation below is a bad idea.

DO NOT USE IN A PRODUCTION SERVER

Don't say I didn't warn you.

This thread pool doesn't honor the fundamentals of java.util.concurrent.Executor, java.util.concurrent.ExecutorService and java.util.concurrent.ThreadFactory, and will cause issues in random components: classloader contexts, java SecurityManager contexts, thread contexts, Thread Locals, and will likely break 3rd party integraions like spring, jsp, security, jaas, jaspi, cdi, session storage, session persistence, ssl parameters, ssl engine state, etc ...

import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.thread.ThreadPool;

public class NoThreadPool extends AbstractLifeCycle implements ThreadPool
{
    private final Object joinLock = new Object();

    @Override
    public void execute(Runnable command)
    {
        Thread thread = new Thread(command);
        thread.setName("NoThreadPool"); // name your thread, helps in debugging later
        thread.start();
    }

    @Override
    public void join() throws InterruptedException
    {
        synchronized (joinLock)
        {
            while (isRunning())
            {
                joinLock.wait();
            }
        }

        while (isStopping())
        {
            Thread.sleep(50);
        }
    }

    @Override
    protected void doStop() throws Exception
    {
        super.doStop();
        synchronized (joinLock)
        {
            joinLock.notifyAll();
        }
    }

    @Override
    public int getThreads()
    {
        return 1; // this pool is always in use
    }

    @Override
    public int getIdleThreads()
    {
        return 100_000; // this pool always has capacity
    }

    @Override
    public boolean isLowOnThreads()
    {
        return false; // this pool is never low on threads
    }
}
Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136
  • Thanks! Understood the downside of "no pooling" where threads are used not just request handling but also many other possible purposes. My ultimate goal is to clean up unintentionally remaining `ThreadLocal` in threads in thread pools, which are out of our control. My question might not be a good question... – Dai MIKURUBE Sep 02 '21 at 04:32
  • But anyway, even though it's not for production use, your answer `NoThreadPool` is interesting to learn for me. Thanks! – Dai MIKURUBE Sep 02 '21 at 04:33