ExecutorService - 在方法中创建新实例与每个 class

ExecutorService - create new instances in method vs one per class

我应该在每个方法调用中创建新的 ExecutorService 还是每个 class 使用一个?就性能而言,哪个是首选?

public class NotificationService {

    public void sendNotification(User recipient) {

        ExecutorService notificationsPool = Executors.newFixedThreadPool(10);

        // code

        notificationsPool.shutdown();
    }
}

或者

public class NotificationService {

    ExecutorService notificationsPool = Executors.newFixedThreadPool(10);

    public void sendNotification(User recipient) {

        // code
    }
}

在您的第一个代码片段中,ExecutorService 是本地的,即在每次方法调用时都会创建一个新的 ExecutorService,并且 ExecutorService 在方法结束时终止。因此,当该方法下次运行时,线程不会被重用。在第二个片段中,只要 NotificationService 实例还活着,ExecutorService 及其线程就会被保留。如您所见,不仅要进行 GC 的 ExecutorService 实例更少,而且要创建的线程也更少,并且可以重用。作为额外的奖励,第二种方法在创建 ExecutorService 之后不会产生任何线程创建的预热时间。

如果您有多个 NotificationService 实例,您应该将 notificationsPool 声明为 static,以便在所有实例之间共享池及其线程。

如果需要的线程数量取决于必须发送的通知数量,请使用缓存线程池 (ExecutorService#newCachedThreadPool()),可能有上限。

这取决于两个问题:

  • 您需要什么级别的并行化?
  • 您可以接受多少间接费用?

你真的需要10个线程来解决函数中的问题吗?您是否需要能够处理该函数两次(从而为其提供 20 个线程)?你有资源吗?

或者如果你给 class 分配一个线程池会发生什么?这样做您可能 运行 会遇到问题吗(由于线程池用完而阻塞)?

如果有足够的资源,选项 1 可能会更快,如果要解决的任务足够大以证明每次调用函数时创建该执行程序的开销是合理的。老实说,我很难想象会有这么强烈的通知。

因此,如果没有更多信息,我会指向选项 2(当然假设它是静态的)。您也可以看看新的 WorkStealingPool,它可能会帮助您使用精确的并行度。