将工作发送到需要初始化的工作池

时间:2012-08-19 02:50:44

标签: java multithreading executor

我遇到的问题似乎与Executor和线程池相似,但我似乎无法使其完全适合。基本上我有工作人员需要花一些时间来初始化,我想要集中,一旦他们准备好了,我就用它们来做工作。我需要在一个线程中执行此操作:

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

虽然执行官只允许我这样做:

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

我是否需要编写自己的线程池?重写已经做得好的事情感觉真是太遗憾了。或者我是否需要使用ThreadLocal来保留我的工作人员,并在Runnable的run()方法中管理它们?

1 个答案:

答案 0 :(得分:5)

如果您在讨论实际初始化Thread对象之前可以使用它们,请查看ThreadPoolExecutor.setThreadFactory:

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

您可以以任何方式提供自己的实现创建线程,包括创建自定义线程子类和/或自定义初始化。

但是,我会说,如果你的初始化很昂贵,你应该尝试配置执行器以尽可能长时间地保持实际线程的活动(即,设置保持活动时间相当高,并尝试启动所有你需要的线程,并在前面点击。

编辑:使用本地线程(如评论中所述):

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(...);

然后在你的Runnable:

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

此外,这种方法(与使用Thread.currentThread()和cast相反)具有能够实际用于任何Thread实现(包括默认)或没有线程(直接调用。在ThreadLocal中设置值后的run()方法)。您还可以轻松地将“ThreadLocal”更改为“InheritableThreadLocal”,并在向线程池提交任何内容之前将其设置一次。所有子线程都将从其父线程(创建池的线程)继承该值。

重要的是要注意,给定线程的“run”方法只会执行一次,即使在线程池中也是如此,因此这可以保证初始化例程在每个线程的基础上发生。