首页 > 解决方案 > ExecutorService 和 Future 正在阻塞主线程

问题描述

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

第一个目标达到了,地形生成比较快,但是每次生成地形时主线程都被阻塞,导致生成时卡顿。

这是我的代码:

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

这是打印的输出:

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

正如你所看到的,我正在使用future.isDone() 方法,但是如果它找到一个完成的future,它仍然会在调用future.get() 时阻塞,证明是我在最后做的打印,它给出了一个第一个未来的时间很长,然后每个未来约 1 毫秒来检索正常行为的信息。

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

编辑

我将脚本隔离在一个最小的可重现项目中并且问题消失了,有罪的行是其中之一//Some instructions,所以首先我将这些行添加到上面的代码中,其次我将继续调查和更新帖子。

我终于隔离了冻结整个过程的一行:

int vaoID = GL30.glGenVertexArrays();

所以基本上,在获得未来之后,我调用terrain.generate它从顶点、法线、颜色等信息创建模型。为了创建模型,我首先创建了一个 vao,创建这个 vao 的第一步是这条线,当它第一次在这个框架中创建时,它会冻结,直到所有其他期货都完成,这太疯狂了!

我不得不说我肯定迷路了,我不知道有什么可做的。

标签: javamultithreadinglwjglfutureexecutorservice

解决方案


推荐阅读