我在从线程使用 JNI 调用本机函数时遇到了一个棘手的问题。
本机函数是执行计算密集型任务的遗留代码。由于我不想冻结程序的其余部分,因此计算应该在后台线程中执行。EventBus https://eventbus.dev.java.net/用于将计算结果发送回主程序。
基本上就可以了should很简单,像这样:
public class CalculationEngine {
private CalculationEngine(){}
public static void calculateInBackground(final Parameters parameters) {
new Thread(new Runnable() {
public void run() {
// Someone might change the parameters while our thread is running, so:
final Parameters clonedParameters = parameters.clone();
Results results = new Results();
natCalc(clonedParameters, results);
EventBus.publish("Results", results);
}
}).start();
}
public static void calculateNormally(final Parameters parameters) {
Results results = new Results();
natCalc(parameters, results);
EventBus.publish("Results", results);
}
private static native synchronized void
natCalc(Parameters parameters, Results results);
}
现在calculateNormally
阻止主程序的方法工作正常,但是calculateInBackground
方法,它只是构造一个后台线程来做同样的事情,导致本机代码中出现各种崩溃当连续调用时。我所说的连续是指只有在前一个线程完成并返回结果后才会再次调用它。注意本机代码已标记synchronized
以确保一次只能运行一个实例。
我的问题是,本机代码到底是如何根据是从主线程调用还是从其他线程调用而表现不同的?当从主线程以外的线程中调用本机代码时,就像本机代码保持“状态”,而不是真正退出。有没有办法在线程完成后“清理”或“冲洗”线程? JNI 和线程中一定有一些我根本不知道的东西。
感谢您的任何提示!
在谷歌搜索并找到这个短语后,我找到了一个可行的解决方案“我发现 JNI 在从单独的线程调用时存在很多错误......因此请确保只有一个线程调用您的本机代码!” http://bytes.com/groups/java/16934-jni-java-threads。这似乎是真的;解决方案是保留一个持久的、“可重用”的线程 - 我用过Executors.newSingleThreadExecutor()
- 并仅从该线程调用本机代码。有用。
因此,从 JNI 的角度来看,区别不在于主线程与其他线程之间,而在于在连续调用中使用不同的线程。请注意,在有问题的代码中,每次都会构造一个新线程。它应该这样工作,但事实并非如此。 (不,我没有缓存 JNIEnv 指针。)
无论是 JNI 错误、本机代码中的错误、它们与操作系统之间的交互还是其他什么,都值得了解。但有时您只是没有机会详细调试 10000 多行现有代码,但是您很高兴让它工作。这是示例代码的工作版本,我们称其为解决方法:
public class CalculationEngine {
private CalculationEngine(){}
private static Parameters parameters;
private static ExecutorService executor = Executors.newSingleThreadExecutor();
private static Runnable analysis = new Runnable() {
public synchronized void run() {
Results results = new Results();
natCalc(parameters, results);
EventBus.publish("Results", results);
}
};
public static synchronized void
calculateInBackground(final Parameters parameters) {
CalculationEngine.parameters = parameters.clone();
executor.submit(analysis);
}
private static native synchronized void
natCalc(Parameters parameters, Results results);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)