java - 在游戏循环中等待 FutureTask 完成

标签 java multithreading concurrency libgdx futuretask

我想为昂贵的路径查找任务设置一个 FutureTask。所以我创建了这个Callable类。

public class GetPath implements Callable<List<Coordinate>> {

    private Coordinate start;
    private Coordinate end;

    public GetPath(Coordinate start, Coordinate end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public List<Coordinate> call() throws Exception {

        IndexedNodeImplementation location = TestMap.mapgraph.getNodeByCoord(start.x, start.y);
        IndexedNodeImplementation destination = TestMap.mapgraph.getNodeByCoord(end.x, end.y);
        GraphPathImplementation resultPath = new GraphPathImplementation();

        List<Coordinate> path = new ArrayList<Coordinate>();

        TestMap.pathFinder.searchNodePath(location, destination, new HeuristicImplementation(), resultPath);

        if (resultPath.getCount() > 0)
        {
            for (int i = 1; i < resultPath.getCount(); i++)
            {
                path.add(new Coordinate(resultPath.get(i).origin(), true));
            }
        }
        return path;
    }
}

当我在构造函数中看到的示例中执行此操作时,它仍然“等待”直到任务完成。虽然这有效,但我仍然遇到丢帧的情况,就好像我只是在没有线程的情况下完成它一样。

executor = Executors.newFixedThreadPool(1);
task = new FutureTask(new GetPath(creature.getLocation(), coordinate));
//TestMap.executor.execute(task);

executor.execute(task);

try {
    path = (List<Coordinate>)task.get();
    } catch (InterruptedException e) {
        System.out.println("Interrupted Exception");
        e.printStackTrace();
    } catch (ExecutionException e) {
        System.out.println("Execution Exception"); // <---
        e.printStackTrace();
    }

    executor.shutdown();
    //Works but is basically the same as just looking up a path in the main thread.

我知道拥有一个线程池是相当愚蠢的,但我对此很陌生。不管怎样,我尝试为每个对象使用相同的 ExecutorService 一个更大的池,但没有成功。

由于此方法仍然保留程序直到完成,所以我尝试在游戏循环中观看 FutureTask 。完成后,我填充路径列表并继续编写代码。

        if (task.isDone())
        {
            try {
                path = (List<Coordinate>)task.get();
            } catch (InterruptedException e) {
                System.out.println("Interrupted Exception");
                e.printStackTrace();
            } catch (ExecutionException e) {
                System.out.println("Execution Exception");
                e.printStackTrace();
            }
            executor.shutdown();
            //TestMap.executor.shutdown();
        }
        else
        {
            return false;
        }
        //Continue with code and work with path which should now contain elements

但这给出了我无法跟踪的NullPointerException。我检查了自己代码中的所有变量,似乎没有任何内容为空。也许我误解了task.isDone 。或者也许我应该将任务留给执行器来处理并使用执行器来确定任务是否完成,但我不确定如何完成。

java.util.concurrent.ExecutionException: java.lang.NullPointerException
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:188)
    at com.buckriderstudio.buriedkingdoms.Creatures.Jobs.GoTo.perform(GoTo.java:55)
//...

我只是想在另一个线程上运行一些昂贵的代码而不中断我的主游戏循环。我不在乎它需要多长时间才能找到路径,这就是为什么我宁愿将其放在单独的线程中,然后尝试实现更好的寻路算法(如分层 A*)。我目前正在使用 gdx.ai.pfa.* 进行寻路。

打开当前程序后,有 100 个单元等待路径。每个游戏循环 1 个单元都会收到一个路径请求。我不确定这是否对我在这里所做的事情有任何影响。

最佳答案

如果您的路径查找Runnable在同步运行时工作正常,但在异步运行时工作正常(您的第二个示例)。我相信您的问题出在您的 Runnable 内部,您正在尝试访问某些资源,但在您访问它时该资源为空。

基本上,在清空(或处置)资源的代码行与需要访问该资源的 Runnable 内的代码之间存在竞争条件。换句话说,当您同步运行它时,Runnable 总是“首先到达那里”,因为程序的其余部分正在等待它完成。在您的情况下,当异步时,处理/清空代码会在 Runnable 获取资源之前执行。

您截取了堆栈跟踪,但最后一行提到了 GoTo.java 中的 perform 方法

您从 Runnable 外部对某些资源执行某些操作,这意味着在执行 Runnable 时,它​​会尝试访问 null 的内容。

关于java - 在游戏循环中等待 FutureTask 完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34089407/

相关文章:

java - 无法发布到带有 "java.lang.IllegalArgumentException: Illegal character in path"的 URL

c++ - 关于使用多线程定期强制检查软件更新的问题

java - 如何在继续当前线程之前等待事件发生?

java - 两个ExecutorServices可以共享一个线程池吗?

java - hibernate createAlias with 子句生成错误的查询

java - 将结果记录到 Excel 文件(apache poi),如果我在程序仍在运行时打开文件,则会出现错误

java - Elasticsearch XContent Provider

c++ - 指针在 OpenMP 并行部分中是私有(private)的吗?

concurrency - Ada 并发问题

concurrency - 使用 lambda 解锁