ExecutorService - 在方法中创建新实例 vs 每个类一个实例

7

在每个方法调用中创建新的ExecutorService还是在类中使用一个?就性能而言,哪个选项更好?

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
    }
}

2
你不是基于性能来选择这个的,而是根据需要来选择。你需要10个新线程来向用户发送通知吗?如果你只使用其中一个线程一次(假设这就是向用户发送通知所需的),那么拥有10个可重用线程池的意义何在呢? - JB Nizet
用户可能与多个键相关联。但是,这并不是一个好的代码示例,因为它在发布之前已经被修改过了。 - Justinas Jakavonis
2个回答

6
在你的第一个代码片段中,ExecutorService 是本地的,即每次方法调用都会创建一个新的 ExecutorService ,并且该 ExecutorService 在方法结束时终止。因此,当方法下一次运行时,线程不会被重复使用。在第二个代码片段中,ExecutorService 及其线程将保持活动状态,只要 NotificationService 实例存在。正如您所看到的,不仅有更少的 ExecutorService 实例需要进行垃圾回收,而且还有更少的线程需要创建,并且它们可以被重复使用。作为额外的奖励,第二种方法在创建 ExecutorService 后不会产生任何线程创建的预热时间。
如果您有多个 NotificationService 实例,则应将 notificationsPool 声明为 static,以便在所有实例之间共享池及其线程。
如果所需线程的数量取决于必须发送的通知数量,请使用缓存线程池(ExecutorService#newCachedThreadPool()),也许带有上限。

1
这取决于两个问题:
1.你需要什么级别的并行化?
2.你可以接受多少开销?
你真的需要10个线程来解决函数中的问题吗?你需要能够处理函数两次(因此给它20个线程)吗?你是否有足够的资源来做到这一点?
或者,如果你为类分配一个线程池,会发生什么?这样做可能会遇到问题(由于线程池被用完而导致阻塞)吗?
在有足够资源的情况下,选项1可能更快,但是只有当要解决的任务足够大,可以证明创建每次执行函数时都需要的执行程序的开销是合理的。尽管老实说,我几乎无法想象那么强烈的通知。
因此,在没有更多信息的情况下,我会选择选项2(当然假设它是静态的)。此外,您还可以查看新的WorkStealingPool,它可能帮助您使用精确的并行级别。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接