Question

I have a problem that seems close to what Executors and Thread pools do, however I can't seem to make it exactly fit. Basically I have workers which take a bit of time to initialize and that I'd like to pool, and once they are ready I use them to do work. I need to do this in a Thread :

worker = buildExpensiveWorker();
worker.doWork(work1);
worker.doWork(work2);
worker.doWork(work3);
...

While an Executor only allows me to do this :

doWork(work1);
doWork(work2);
doWork(work3);
...

Will I need to write my own Thread pool ? It feels like a shame to rewrite what is already well done. Or will I need to use ThreadLocal to hold my workers, and manage them from inside the Runnable's run() method ?

Was it helpful?

Solution

If you're talking about actually initializing the Thread objects prior to them being available for use, take a look at ThreadPoolExecutor.setThreadFactory:

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html#setThreadFactory(java.util.concurrent.ThreadFactory)

You can provide your own implementation create a thread in any manner you want, including creating custom Thread subclasses and/or custom initialization.

I would say however, that if your initialization is expensive, you should probably try to configure the executor to keep the actual threads alive as long as possible (ie, set the keep alive time rather high, and try to spin up all the threads you need right away, and take the hit up front).

EDIT: Using a thread local (as mentioned in the comments):

public class ThreadData {
    public static final ThreadLocal<String> data = new ThreadLocal<String>();
}

public class InitializingThread extends Thread {
    public InitializingThread(Runnable r) {
        super(r);
    }

    public void run() {
        ThreadData.data.set("foo");
        super.run();
    }
}

public class InitializingThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
        return new InitializingThread(r);
    }
}

ThreadPoolExecutor executor = ...;
executor.setThreadFactory(new InitializingThreadFactory());
executor.execute(...);

And then in your Runnable:

public void run() {
     String s = ThreadData.data.get();
}

Also, this approach (as opposed to using using Thread.currentThread() and casting) has the advantage of being able to actually be used with any Thread implementation (including the default), or without a thread (directly calling the .run() method after setting the value in the ThreadLocal). You could also easily change "ThreadLocal" to "InheritableThreadLocal", and set it once before submitting anything to the thread pool. All child threads would inherit the value from their parent thread (the one which created the pool).

It's important to note that the "run" method of a given thread will only ever executed once, even when in a thread pool, so this guarantees that your initialization routine happens on a per thread basis.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top