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
).