5

I'm trying to write a mechanism that loads a few models concurrently (using ExecutorService) and retrieves their results when all are finished:

List<Future<Model>> modelFutures = new LinkedList<Future<Model>>();
ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE);
List<Model> models = new ArrayList<Model>();
for (ClassifierConfig classifierConfig : classifiers) {
    try {
        final String modelFileName = classifierConfig.name + ".model";
        modelFutures.add(executor.submit(new InitModelTask(MODELS_LOCAL_DIR + SEP + modelFileName)));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

for (Future<Model> modelFuture : modelFutures) {
    try {
        models.add(modelFuture.get(MAX_REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
    } catch (Exception e) {
        System.out.println("Timeout occurred when loading models ");
    }
}
executor.shutdown();
return models;

The task class is as follows:

public class InitModelTask implements Callable<Model> {

    private String modelFileName;

    public InitModelTask(String modelFileName) {
        this.modelFileName = modelFileName;
    }

    @Override
    public Model call() throws Exception {
        return WekaModuler.loadModel(modelFileName, Model.class);
    }
}

This code works.

However, I wanted to make it more elegant by getting rid of the InitModelTask class and converting it to an inline Callable, by calling the executor's submit() method in the following fashion:

modelFutures.add(executor.submit(() -> WekaModuler.loadModel(MODELS_LOCAL_DIR + SEP + modelFileName)));

This passes compilation, runs, creates the executor service thread pool, but when the time comes to call the actual callable, it's just stuck. I tried putting a breakpoint inside WekaModuler::loadModel and it never stops there. I looked at the thread dump and all of the threads in the thread pool are in state RUNNABLE and specifying the following stack trace:

"pool-2-thread-13" #27 prio=5 os_prio=0 tid=0x000000001da52000 nid=0xd78 in Object.wait() [0x0000000021fdf000]
   java.lang.Thread.State: RUNNABLE
        at com.evercompliant.weka.classifier.EverClassifier$$Lambda$4/1222094219.call(Unknown Source)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

Should there be any difference between the inline Callable and the actual Callable-implementing class?

I must point out that I tried to simulate the same thing with some dummy tasks that return Future<Integer> and everything worked fine and as expected. That finding points to a problem with the actual domain (WekaModuler).

KidCrippler
  • 1,633
  • 2
  • 19
  • 34

0 Answers0