I'm developing a game in java and I implemented a multi-threading system to perform a terrain generation which is a repetitive task (~10-20 tasks, each taking ~10-20ms, in one frame). The goal is to:
Divide the time the tasks are taking, because I don't want my player to have a freeze whenever terrain is generating.
Don't wait for the terrains to generate. For example, if I am moving and the terrains in front of me are still generating, I don't want the main thread to wait until the terrains are generated, I want the game to continue running until the future is done and the info is retrieved to render the terrain.
The first goal is reached, the terrains are relatively fast to generate, but the main thread is blocked whenever I generate terrains, causing a freeze when generating.
Here is my code:
//method called each frame
private void checkForFutures(List<Future<SomeClass>> terrainsInCreation) {
System.out.println("NEW CHECK");
try
{
List<Future<SomeClass>> futuresToRemove = new ArrayList<Future<SomeClass>>();
for(Future<SomeClass> future:terrainsInCreation) {
if(future.isDone()) {
float time = DisplayManager.getCurrentTime();
try {
SomeClass t = future.get();
// Some instructions (EDIT:)
Key key = new Key(t.terrain.getChunkX(),t.terrain.getChunkZ());
t.terrain.generateTerrain(loader, t.vertices, t.indices,t.colors, t.normals); // Guilty line !
terrains.put(key, t.terrain);
terrainsToRender.add(t.terrain);
futuresToRemove.add(future);
} catch (ExecutionException e) {
e.printStackTrace();
Thread.sleep(1000000);
}
System.out.println("future done, took: " + (DisplayManager.getCurrentTime()-time));
// The first future is always taking ~ 100-200ms, which is the time it takes to generate all the terrains
// roughly divided by 4, which is the numbers of core I have
}
}
terrainsInCreation.removeAll(futuresToRemove);
}
catch (InterruptedException ie)
{
System.err.println("BIG PROBLEM ON TERRAIN MANAGER");
}
}
//method called when I have terrains to generate
private void generate(List<Callable<SomeClass>> terrainsToCreate) {
for(int i = 0; i < terrainsToCreate.size();i++) {
terrainsInCreation.add(executor.submit(terrainsToCreate.get(i)));
}
}
Here is the output of the print:
NEW CHECK
NEW CHECK
NEW CHECK
NEW CHECK
future done, took: 165.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 0.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 2.0
future done, took: 1.0
future done, took: 0.0
future done, took: 1.0
future done, took: 0.0
future done, took: 1.0
future done, took: 1.0
future done, took: 1.0
future done, took: 2.0
future done, took: 0.0
future done, took: 1.0
future done, took: 2.0
future done, took: 2.0
future done, took: 0.0
future done, took: 0.0
NEW CHECK
NEW CHECK
NEW CHECK
NEW CHECK
As you can see I'm using the future.isDone() method, but if it finds a done future, it still blocks when calling future.get(), the proof is the print I'm doing at the end which give a large time for the first future, and then ~1ms for each future to retrieve the info which is normal behavior.
My question is how to literally execute the tasks in parallel, and retrieve the results when finished but without blocking the main thread at all? (The not finished futures shouldn't be awaited)
Edit
I isolated the script in a minimal reproducible project and the issue was gone, the guilty line is one of the //Some instructions , so first I added these lines to the code above, and second I'll keep investigating and update the post.
I finally isolated the one line that freezes the whole process:
int vaoID = GL30.glGenVertexArrays();
So basically, after getting the future I call terrain.generate which creates a model from the vertices, normal, colors etc infos. To create the model, I first create a vao, and the first step to create this vao is this line and the first time it gets created in this frame, it freezes until every other futures are done this is insane!
I have to say that I'm definitely lost and I don't know a single thing to do.