【问题标题】:How to initialize all threads of a fixed thread pool before submitting any tasks? (JAVA)如何在提交任何任务之前初始化固定线程池的所有线程? (JAVA)
【发布时间】:2015-08-07 08:54:01
【问题描述】:

我正在尝试加速使用ExecutorService 并行运行任务的程序。它基本上是这样工作的:

  1. 初始化大小为n的固定大小线程池

  2. 读取一堆(大约 2500 个文件)包含任务输入的 XML 文件

  3. 使用池中的工作线程处理 XML 文件

一切都按预期工作,但我遇到的问题是每个工作线程都有一个对输入数据进行计算的类的实例。此实例存储在ThreadLocal 中。现在,所有这些线程本地实例都是在启动相应的工作线程时创建的,这意味着在读取所有 XML 输入文件之后。

由于计算对象的初始化需要相当长的时间,我宁愿让线程池从一开始就初始化所有工作线程,以便计算对象的初始化可以与输入文件的读取并行运行。

这里有一些代码可以帮助您了解它当前的工作方式(我删除了与问题无关的代码)。

初始化线程池和线程本地:

  private final ExecutorService executor = Executors.newFixedThreadPool(Math.max(1, Runtime
      .getRuntime().availableProcessors() - 1));

  private ThreadLocal<Calculator> calculator = new ThreadLocal<Calculator>() {
    @Override
    protected Calculator initialValue() {
      try {
        Calculator instance = createCalculator();
        return instance;
      } catch (Throwable e) {
        throw new RuntimeException(e);
      }
    }
  };

提交新的计算:

  @Override
  public FutureTask<Output> calc(Input input) {
    FutureTask<Output> task = new FutureTask<>(
        new Callable<Rueckgabe>() {
          @Override
          public Output call() throws Exception {
            try {
              return calculator.get().calc(input);
            } catch (Throwable e) {
              System.err.println("Exception: " + e.getMessage());
              e.printStackTrace(System.err);
              return null;
            }
          }
        });
    executor.execute(task);
    return task;
  }

ExecutorService 从一开始就为池启动所有工作线程的正确方法是什么?还是我必须使用 n 虚拟任务来强制初始化?

PS:由于 IT 限制,我必须在可预见的未来使用 Java 7。

【问题讨论】:

  • 似乎我在 JDK 源代码中找到了一些东西。我可以将Executors.newFixedThreadPool 的返回值转换为ThreadPoolExecutor 并调用prestartAllCoreThreads:((ThreadPoolExecutor) executor).prestartAllCoreThreads()。但是没有一种干净的方法可以做到这一点(即不依赖newFixedThreadPool() 实现并且需要强制转换)?
  • Executors API 只是为了简化常见用例的使用。当您需要更多控制权时,请自行实例化ThreadPoolExecutor。它与 Executors 一样是公共 API。

标签: java multithreading threadpool executorservice


【解决方案1】:

向执行初始化的执行器添加一个线程工厂。

executor = Executors.newFixedThreadPool(numprocrssors, new ThreadFactory ( ){
    public Thread newThread(Runnable r) {
        return new Thread(r){
            {calculator.get();} // this is an initialization statement, added to all constructors.
        };
    }});

【讨论】:

  • 谢谢,我最终按照建议使用了ThreadFactory,但使用ThreadPoolExecutor pool = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue&lt;Runnable&gt;(), threadFactory); 实例化了池,然后调用了pool.prestartAllCoreThreads()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2017-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多