在游戏循环中等待 FutureTask 完成
Wait for FutureTask completion in game loop
我想为昂贵的寻路任务设置 FutureTask
。所以我创建了这个 Callable
class.
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;
}
}
当我在一个示例中执行此操作时,我在构造函数中看到它仍然 "waits" 直到任务完成。虽然这有效,但我仍然遇到帧丢失,就好像我会在没有线程的情况下那样做。
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 个单元得到一个路径请求。我不确定这是否对我在这里所做的有任何影响。
如果您查看 Future
的 Javadoc,您会看到 get
等待任务完成。如果你改为在你的游戏循环中检查 isDone
并且只调用 get
一次 returns true
那么你将 运行 异步。这就是第二个代码块 运行 有效单线程的原因。
在下一个例子中它会更好并且会 运行 异步但是你每次循环都调用它,这意味着你关闭 ExecutorService
但任务仍然完成所以你然后再次调用 isDone
和 get
。第二次可能是生成 NullPointerException
的原因。您很可能需要一些东西来阻止它被重复调用,例如将 task
设置为 null 并检查 task!=null && task.isDone()
.
您还应该只在程序开始时创建一个 ExecutorService
然后重复使用它,而不是不断地创建一个然后关闭它。
您还需要多考虑一下这个问题,例如,如果您在旧路径完成之前尝试计算一条新路径,会发生什么情况?或者路径改变了?
如果您的路径查找 Runnable
在 运行 同步时工作正常,但在 运行 异步时(您的第二个示例)。我相信您的问题出在 Runnable
内部,您正在尝试访问某些资源,该资源在您访问时为 null。
您基本上在清空(或处置)资源的代码行与 Runnable 中需要访问它的代码之间存在竞争条件。换句话说,当您 运行 它同步时,Runnable 总是 "gets there first",因为程序的其余部分正在等待它完成。在您的情况下,当它异步时,disposing/nulling 代码在 Runnable 获取资源之前执行。
您截断了堆栈跟踪,但最后一行在 GoTo.java
中提到了一个 perform
方法
您从 Runnable 外部对某些资源进行了一些操作,这意味着,在执行 运行nable 时,它正在尝试访问 null 的内容。
我想为昂贵的寻路任务设置 FutureTask
。所以我创建了这个 Callable
class.
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;
}
}
当我在一个示例中执行此操作时,我在构造函数中看到它仍然 "waits" 直到任务完成。虽然这有效,但我仍然遇到帧丢失,就好像我会在没有线程的情况下那样做。
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 个单元得到一个路径请求。我不确定这是否对我在这里所做的有任何影响。
如果您查看 Future
的 Javadoc,您会看到 get
等待任务完成。如果你改为在你的游戏循环中检查 isDone
并且只调用 get
一次 returns true
那么你将 运行 异步。这就是第二个代码块 运行 有效单线程的原因。
在下一个例子中它会更好并且会 运行 异步但是你每次循环都调用它,这意味着你关闭 ExecutorService
但任务仍然完成所以你然后再次调用 isDone
和 get
。第二次可能是生成 NullPointerException
的原因。您很可能需要一些东西来阻止它被重复调用,例如将 task
设置为 null 并检查 task!=null && task.isDone()
.
您还应该只在程序开始时创建一个 ExecutorService
然后重复使用它,而不是不断地创建一个然后关闭它。
您还需要多考虑一下这个问题,例如,如果您在旧路径完成之前尝试计算一条新路径,会发生什么情况?或者路径改变了?
如果您的路径查找 Runnable
在 运行 同步时工作正常,但在 运行 异步时(您的第二个示例)。我相信您的问题出在 Runnable
内部,您正在尝试访问某些资源,该资源在您访问时为 null。
您基本上在清空(或处置)资源的代码行与 Runnable 中需要访问它的代码之间存在竞争条件。换句话说,当您 运行 它同步时,Runnable 总是 "gets there first",因为程序的其余部分正在等待它完成。在您的情况下,当它异步时,disposing/nulling 代码在 Runnable 获取资源之前执行。
您截断了堆栈跟踪,但最后一行在 GoTo.java
perform
方法
您从 Runnable 外部对某些资源进行了一些操作,这意味着,在执行 运行nable 时,它正在尝试访问 null 的内容。