Invoking time-consuming JNI task as a thread

前端 未结 4 2097
慢半拍i
慢半拍i 2021-02-10 20:10

I\'m having a tough problem with invoking a native function using JNI from a thread.

The native function is legacy code that performs a computation-intensive task. Since

4条回答
  •  北恋
    北恋 (楼主)
    2021-02-10 20:38

    I figured out a working solution, after googling and finding the phrase "I've found JNI to be very buggy when called from seperate threads... So make sure only one thread ever calls your native code!". It seems to be true; the solution is to keep a persistent, "reusable" thread around - I used Executors.newSingleThreadExecutor() - and to call the native code only from that thread. It works.

    So the difference from JNI point of view was not between main thread vs. some other thread, but in using different threads in consecutive calls. Note that in the problematic code a new thread was constructed each time. It should work that way, but it doesn't. (And no, I'm not caching JNIEnv pointer.)

    Whether it's a JNI bug, bug in the native code, something in the interaction between them and OS or whatever, would be interesting to know. But sometimes you just have no chance to debug 10000+ lines of existing code in detail, however, you're happy to get it to work. Here's working version of the example code, let's call this a workaround:

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

提交回复
热议问题