Java ExecutorService和Future正在阻塞主线程

Java ExecutorService和Future正在阻塞主线程,java,multithreading,lwjgl,future,executorservice,Java,Multithreading,Lwjgl,Future,Executorservice,我正在用java开发一个游戏,我实现了一个多线程系统来执行地形生成,这是一项重复性任务(约10-20个任务,每个任务在一帧中耗时约10-20毫秒)。目标是: 划分任务所花费的时间,因为我不希望我的玩家在地形生成时冻结 不要等待地形生成。例如,如果我正在移动,而我前面的地形仍在生成,我不希望主线程等待地形生成,我希望游戏继续运行,直到将来完成并检索信息以渲染地形 实现了第一个目标,地形生成速度相对较快,但每当我生成地形时,主线程都会被阻塞,导致生成时冻结 这是我的密码: //method

我正在用java开发一个游戏,我实现了一个多线程系统来执行地形生成,这是一项重复性任务(约10-20个任务,每个任务在一帧中耗时约10-20毫秒)。目标是:

  • 划分任务所花费的时间,因为我不希望我的玩家在地形生成时冻结

  • 不要等待地形生成。例如,如果我正在移动,而我前面的地形仍在生成,我不希望主线程等待地形生成,我希望游戏继续运行,直到将来完成并检索信息以渲染地形

实现了第一个目标,地形生成速度相对较快,但每当我生成地形时,主线程都会被阻塞,导致生成时冻结

这是我的密码:

//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)));
        } 
    }
如您所见,我使用的是future.isDone()方法,但如果它找到了一个已完成的未来,它在调用future.get()时仍然会阻塞,证明是我在最后所做的打印,它为第一个未来提供了大量时间,然后为每个未来~1ms来检索信息,这是正常行为

我的问题是如何并行执行任务,并在完成时检索结果,但根本不阻塞主线程?(未完成的期货不应等待)

编辑

我在一个最小的可复制项目中隔离了脚本,问题消失了,有罪的一行是
//一些指令中的一行,因此首先我将这些行添加到上面的代码中,然后我将继续调查并更新帖子

我最终隔离了一条冻结整个过程的线路:

int vaoID = GL30.glGenVertexArrays();
因此,基本上,在获得未来后,我调用
terrain.generate
,它根据顶点、法线、颜色等信息创建一个模型。要创建模型,我首先创建一个vao,创建这个vao的第一步是这条线,当它第一次在这个框架中创建时,它会冻结,直到其他所有的未来都完成了,这太疯狂了


我必须说,我肯定迷路了,我一件事也不知道该怎么办。

我认为TerrainIncreation.add()被阻塞了。get()函数阻止正在运行的线程。如果您使用的是Java 8或更高版本,我建议使用CompletableFuturAt,它不会解释报告的计时,@MrNobody
TerraInIncreation.add()
不在计时区域内,而
future.get()
仅为正在完成的报告调用。您是否检查了
DisplayManager.getCurrentTime()
?我没有看到您的方法中存在明显的缺陷,尽管我们需要一个明确的答案。根据提供的信息,我倾向于认为您的
ExecutorService
为您提供的服务很差。您可以尝试将其转换为不同的实现,您可以考虑将其隔离并在工作负载上进行测试以研究该问题(并且能够测试其他实现)。一旦地形生成完成,就应该考虑使用倒计时锁存器来恢复主线程。让每个未来任务减少闩锁,当闩锁达到零时,bam。这样你就不必跟踪他们的未来或民意调查了。
int vaoID = GL30.glGenVertexArrays();