我有一个 CPP ThreadMgr,它在初始化时创建 100 个 CPP 本机线程(线程池)。
现在,为了进行 JNI 调用并与 Java 交互,我必须使用 AttachCurrentThread 将线程附加到 JVM,并且在终止(正常或突然)这些线程之前,我必须 DetachCurrentThread。
我的方法是在创建时将所有本机线程(在本例中为 100 个)附加到 JVM,并且只有当我终止线程时,我才会将其与 JVM 分离。
在采用这种方法之前,我想列出其优点和缺点,以确定它是否是一个值得遵循的好方法。
我能想到的一些优点/缺点,
优点:
缺点:
可能有些线程在其生命周期中永远不会进行任何 JNI 调用,但我仍然会进行将它们附加/分离到 JVM 的开销调用。
当一个线程附加到 JVM 时,它必须为附加线程分配一些资源,即使附加线程完成了所有 JNI 调用,只有在线程终止前分离时,资源才会释放。
如果我错过了这种方法的任何优点/缺点,以及这是否是一个值得遵循的好方法,请告诉我。
优点:
- 向 JVM 附加和分离本机线程会产生一些性能开销。通过在创建线程时附加一次并 在终止前分离一次,我们可以最大限度地减少这种开销 与每次 JNI 调用的附加和分离相比 线程。
确实如此,但这种收益的重要性取决于工作量。如果附加和分离的开销相对于任务本身的主要工作来说很大,那么在该任务的上下文中,首先考虑使用线程池运行它的开销可能也是合适的。非常快的任务可能最好直接运行,而不是通过线程池。
缺点:
- 可能有些线程在其生命周期中永远不会进行任何 JNI 调用,但我仍然会进行附加/分离的开销调用 它们到 JVM。
是的。但是,如果您的线程池大小合理,并且总体工作足以证明线程池的合理性,那么该开销可能微不足道。
另一方面,如果在其生命周期内提交到池的任务中没有需要 JVM,那么根本不启动一个任务可能会节省大量资源。
确实如此。事实上,当线程分离时,为 JVM 内的线程分配的资源甚至可能不会立即被清理。但这的重要性取决于很多因素,当然,它会随着附加线程的数量而变化。当线程附加到 JVM 时,即使附加线程已完成,它也必须为附加线程分配一些资源 对于所有 JNI 调用,只有在以下情况下才会释放资源: 线程在终止前被分离。
我认为您应该更多地关注更高层次的设计考虑,首先考虑线程池是否是满足您需求的最佳选择。如果您认为池确实合适,那么请考虑您是否真的需要或想要推出自己的池。我认为你可能不这样做,如果你不自己推出,那么这个问题很可能没有意义。无论如何,首先关注良好的设计,
然后编写良好的实现。
还要考虑可能存在可行的混合方法。例如,您可能想要维护单独的 JVM 附加线程池和非 JVM 附加线程池。或者,您可能希望池线程根据需要自适应地附加,然后保持附加状态直到池关闭。