【问题标题】:Sending work to a pool of workers that need initialization将工作发送到需要初始化的工作人员池
【发布时间】:2012-08-19 02:50:43
【问题描述】:

我有一个问题似乎与Executors 和线程池所做的很接近,但我似乎无法让它完全适合。基本上我有一些工人需要一些时间来初始化并且我想集中起来,一旦他们准备好我就用它们来工作。我需要在线程中执行此操作:

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

虽然 Executor 只允许我这样做:

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

我需要编写自己的线程池吗?重写已经做得很好的东西感觉很可惜。还是我需要使用ThreadLocal 来持有我的工人,并从Runnable 的run() 方法内部管理他们?

【问题讨论】:

  • 您可能应该使用ThreadPoolExecutor 并重构您当前的设计,使其适合没有自定义“工人”。如果您不想这样做,那么是的,您可能需要实现自己的。

标签: java multithreading executor


【解决方案1】:

如果您说的是在 Thread 对象可用之前实际初始化它们,请查看 ThreadPoolExecutor.setThreadFactory:

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

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

但是,我想说,如果您的初始化成本很高,您可能应该尝试配置执行程序以尽可能长时间地保持实际线程处于活动状态(即,将保持活动时间设置得相当高,并尝试启动所有线程您需要立即使用的线程,并提前做好准备)。

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

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() 和强制转换相反)具有能够实际用于任何线程实现(包括默认)或没有线程(直接调用 .在 ThreadLocal 中设置值后的 run() 方法)。您还可以轻松地将“ThreadLocal”更改为“InheritableThreadLocal”,并在向线程池提交任何内容之前设置一次。所有子线程都将从其父线程(创建池的那个线程)继承该值。

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

【讨论】:

  • 我的问题是 Runnables 以无状态方式执行。您是否建议提供我自己的 ThreadFactory 然后使用 Thread.getCurrentThread() 来获取我的工人?这会奏效。
  • 是的。使用您需要的任何状态创建您自己的线程实现,并将 Thread.currentThread() 转换为您的类。另一种方法是在某处创建一个公共静态 ThreadLocal 实例,并在调用 super.run() 之前让您的线程类在 run 方法中填充它。这会将您的 Runnable 绑定到 ThreadLocal 而不是实际的 Thread 实现类,但这只是样式问题。
  • @Matt:很好的回答,非常感谢和 1+ 的投票。你有关于使用 ThreadLocal 来解决这个问题的链接吗?
  • 可以用预初始化的worker创建ThreadPoolExecutor吗?在您的示例中,线程创建和初始化是在调用 executor.execute() 时发生的。我想将作业发送到线程池包含在线程池创建时初始化的工作人员的队列,并且可以立即接手工作。
猜你喜欢
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多