这可能是一个有许多可能答案的问题,但我要求的是最好的设计,而不是“如何做到这一点”。
让我们假设我们正在实现一个具有计算Pi的UI的程序。我可以点击" start“按钮开始计算,点击"Stop”按钮中止计算,得到迄今为止计算出的Pi精度值最高的消息框。
我想直接的方法应该是在一个新的线程中开始一个Runnable。runnable计算Pi,并将当前值存储在两个线程都可以访问的共享变量中。"Stop“将中止Thread,并显示共享变量。
不过,我有一种感觉,这可以更优雅地实现,但我不确定如何实现。也许使用CompletableFuture?
我宁愿在不向我的项目添加任何新库的情况下解决这个问题,但是如果你知道有一个库对此支持得特别好,请在评论中留下它。
显然,计算Pi永远不会结束。不过,如果解决方案还支持计算国际象棋中的最佳走法,那就太好了。如果有足够的时间,它将完成,但通常必须中止,返回到目前为止最好的移动。
发布于 2016-06-06 18:10:12
参考你的计算Pi或计算国际象棋中的最佳走法的例子,你的近似算法本质上是迭代的。例如Pi的随机抽样和国际象棋的MCMC。这让我想到了两个appraoches。
1.使用threadsafe标志
Cou可以使用AtomicBoolean,它是一个线程安全布尔型变量。你需要把它传递给你的Runnable,让它在计算近似值时检查它的状态。同时你可以按listener来停止计算,这样就可以设置变量了。
2.计算小块
该算法的迭代性质使得拆分计算和稍后再次聚合计算成为可能。例如,你计算1000次迭代,你可以将其分成200次迭代的块,计算这5个块,并聚合结果。
我现在建议使用ExecutorCompletionService和TimerTask。这个想法是计算少量的迭代,这只需要很短的时间,并使用TimerTask用新的Runnable“重新填充”Executor。假设计算5个runnables需要1秒,你的计时器任务将每1秒将5个Runnables放入Executor中。当您点击停止按钮时,您将停止派生,并只等待挂起的任务完成,收集它们的结果,并有一个结果。
当然,你还需要一个变量来告诉TimerTask在调用完成服务的关闭方法后停止,但这个不一定是线程安全的。这种方法的另一个好处是,您的计算是并发的,并且您可以轻松地充分利用任何CPU,只需生成更多Runnables即可。同时这样做可以让你在更短的时间内计算更多,并获得更好的近似值。
发布于 2016-06-06 18:14:08
你的问题是如何实现一个仍能交付结果的可停止任务。近似值是一个很好的例子,但在求解过程中可以忽略不计。
例如,FutureTask不会工作,因为他们的合同是他们自己决定何时完成,他们只能有一个结果或被取消。
共享(例如volatile)变量听起来合理,但也有它的缺点。当在一个紧密的循环中定期更新时,你可能会观察到比使用局部变量更差的性能,并且只有当对象是不可变的或者可以保证以正确的顺序进行读写时,读取共享对象的状态才是安全的。
您还可以使用结果交付BlockingQueue构建一些东西,一旦请求中断,计算线程就会将当前结果(甚至是对结果的定期更新)放入其中。
但最好的解决方案可能是(共享的) CompletableFuture。这是一种单一的结果项队列,但它具有更好的异常报告语义。
示例:
CompletableFuture<Integer> sharedFuture = new CompletableFuture<>();
Thread computing = new Thread(() -> {
int value = 1;
try {
while (!Thread.currentThread().isInterrupted() &&
!sharedFuture.isDone()) { // check could be omitted
value = value * 32 + 7;
}
sharedFuture.complete(value);
} catch (Throwable t) {
sharedFuture.completeExceptionally(t);
}
});
computing.start();
try {
Thread.sleep((long) (5000 * Math.random()));
} catch (InterruptedException ignored) {
}
computing.interrupt();
System.out.println(sharedFuture.get());http://ideone.com/8bpEGV
你如何执行这项任务并不重要。除了上面的Thread,您还可以使用ExecutorService,然后取消Future,而不是中断线程。
https://stackoverflow.com/questions/37653733
复制相似问题