【问题标题】:Java Executor Service Start Threads when Application LaunchesJava Executor Service 在应用程序启动时启动线程
【发布时间】:2019-03-21 22:00:20
【问题描述】:

当我的应用程序启动时,会创建一个执行程序服务(使用 java.util.concurrent 中的 Executors.newFixedThreadPool(maxThreadNum))对象。当请求到来时,执行器服务会创建线程来处理它们。

因为在运行时创建线程需要时间,所以我想在启动应用程序时使线程可用,这样当请求到来时,处理时间会更少。

我所做的如下:

executorService = Executors.newFixedThreadPool(200);
for (int i=0; i<200; i++) {
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("Start thread in pool " );
        }
    });
}

应用启动时会在executorService池中创建200个线程。

只是想知道这是在应用程序启动时创建线程的正确方法吗? 还是有更好的方法?

【问题讨论】:

  • 这是正确的,这就是发明线程池的确切原因。消除线程的创建延迟。

标签: java executorservice java-threads


【解决方案1】:

您缺少shutdown()。操作完成后关闭Executor服务非常重要。 try,catch and Finally block 也是如此

try{ executorService.execute(...); }catach(Exception e){ ... }finally{ executorService.shutdown(); //Mandatory }

【讨论】:

  • 这不是 OP 所要求的。
  • 好吧,他在问他的实现是否正确.. 关闭也是必要的,否则线程会继续在后台运行。它不会立即关闭。
  • 你是对的,但这应该作为评论发布。答案应该能回答问题。
  • 感谢您指出这一点!将使用 try、catch、finally 阻止异常。
【解决方案2】:

如果您可以直接使用ThreadPoolExecutor 而不是来自Executors1ExecutorService,那么可能有一种更标准/受支持的方式来立即启动所有核心线程。

int nThreads = 200;
ThreadPoolExecutor executor = new ThreadPoolExecutor(nThreads, nThreads, 
        0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
executor.prestartAllCoreThreads();

以上使用prestartAllCoreThreads()

请注意,目前Executors.newFixedThreadPool(int) 的实现以与上述完全相同的方式创建ThreadPoolExecutor。这意味着您可以在技术上将工厂方法返回的ExecutorService 转换为ThreadPoolExecutor。但是,文档中没有任何内容保证它将是ThreadPoolExecutor


1. ThreadPoolExecutor 实现了ExecutorService,但提供了更多功能。此外,Executors 中的许多工厂方法要么直接返回 ThreadPoolExecutor,要么返回一个委托给其中的包装器。有些人,比如newWorkStealingPool,使用ForkJoinPool。同样,这些工厂方法的返回类型是实现细节,所以不要过分依赖它。

【讨论】:

    【解决方案3】:

    如果您的代码适用于您的场景,它就完全没问题。由于我们不了解您的用例,因此只有您可以通过足够的测试和基准来回答您的问题。

    但是,请注意线程池会在一段时间后回收空闲线程。如果你不注意它可能会咬你。

    【讨论】:

    • 谢谢!请注意,普通线程池(如果不是 FixedThreadPool)会在一段时间后回收空闲线程!
    • 抱歉,这可能不是真的。具体来说,只有 CachedThreadPool 会在 60 秒后回收空闲线程
    【解决方案4】:

    只是想知道这是在应用程序时创建线程的正确方法吗 开始了吗?

    是的。这是创建线程的正确方法。

    或者有更好的方法吗?

    也许吧。在某些工作负载下,您可能希望使用具有可变数量线程的线程池(与 newFixedThreadPool 创建的线程池不同) - 一个从池中删除已空闲一段时间的线程。

    【讨论】:

    • 它不会删除空闲一段时间的线程-文档链接-docs.oracle.com/javase/8/docs/api/java/util/concurrent/…
    • 这就是我写的——固定池不这样做。其他一些游泳池可以。
    • 谢谢先生的帮助! FixedThreadPool 的使用是我同事设计的,这个会跟他们核实。
    【解决方案5】:

    可以并行运行的线程数取决于您的处理器内核。除非你有 200 个内核,否则创建 200 个线程池将毫无用处。

    了解您拥有多少个处理器内核的好方法是:

    int cores = Runtime.getRuntime().availableProcessors();
    

    此外,在创建和执行新线程期间产生的开销是不可避免的,因此除非任务计算量很大,否则不值得为此任务创建新的单线程。

    但毕竟到目前为止,您的所有代码都很好。

    【讨论】:

    • “除非你有 200 个内核,否则创建 200 个线程池将毫无用处” - 如果线程正在执行 I/O,则不是这样。
    • 真的吗?我不知道那件事。谢谢
    • 我的桌面是8核的,不知道测试服务器有多少核。这个号码是我同事之前给的,会和他们讨论这个。谢谢!
    猜你喜欢
    • 2014-05-20
    • 2016-08-05
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多