首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Java中并发计算近似值?

如何在Java中并发计算近似值?
EN

Stack Overflow用户
提问于 2016-06-06 17:20:47
回答 2查看 129关注 0票数 2

这可能是一个有许多可能答案的问题,但我要求的是最好的设计,而不是“如何做到这一点”。

让我们假设我们正在实现一个具有计算Pi的UI的程序。我可以点击" start“按钮开始计算,点击"Stop”按钮中止计算,得到迄今为止计算出的Pi精度值最高的消息框。

我想直接的方法应该是在一个新的线程中开始一个Runnable。runnable计算Pi,并将当前值存储在两个线程都可以访问的共享变量中。"Stop“将中止Thread,并显示共享变量。

不过,我有一种感觉,这可以更优雅地实现,但我不确定如何实现。也许使用CompletableFuture?

我宁愿在不向我的项目添加任何新库的情况下解决这个问题,但是如果你知道有一个库对此支持得特别好,请在评论中留下它。

显然,计算Pi永远不会结束。不过,如果解决方案还支持计算国际象棋中的最佳走法,那就太好了。如果有足够的时间,它将完成,但通常必须中止,返回到目前为止最好的移动。

EN

回答 2

Stack Overflow用户

发布于 2016-06-06 18:10:12

参考你的计算Pi或计算国际象棋中的最佳走法的例子,你的近似算法本质上是迭代的。例如Pi的随机抽样和国际象棋的MCMC。这让我想到了两个appraoches。

1.使用threadsafe标志

Cou可以使用AtomicBoolean,它是一个线程安全布尔型变量。你需要把它传递给你的Runnable,让它在计算近似值时检查它的状态。同时你可以按listener来停止计算,这样就可以设置变量了。

2.计算小块

该算法的迭代性质使得拆分计算和稍后再次聚合计算成为可能。例如,你计算1000次迭代,你可以将其分成200次迭代的块,计算这5个块,并聚合结果。

我现在建议使用ExecutorCompletionServiceTimerTask。这个想法是计算少量的迭代,这只需要很短的时间,并使用TimerTask用新的Runnable“重新填充”Executor。假设计算5个runnables需要1秒,你的计时器任务将每1秒将5个Runnables放入Executor中。当您点击停止按钮时,您将停止派生,并只等待挂起的任务完成,收集它们的结果,并有一个结果。

当然,你还需要一个变量来告诉TimerTask在调用完成服务的关闭方法后停止,但这个不一定是线程安全的。这种方法的另一个好处是,您的计算是并发的,并且您可以轻松地充分利用任何CPU,只需生成更多Runnables即可。同时这样做可以让你在更短的时间内计算更多,并获得更好的近似值。

票数 2
EN

Stack Overflow用户

发布于 2016-06-06 18:14:08

你的问题是如何实现一个仍能交付结果的可停止任务。近似值是一个很好的例子,但在求解过程中可以忽略不计。

例如,FutureTask不会工作,因为他们的合同是他们自己决定何时完成,他们只能有一个结果或被取消。

共享(例如volatile)变量听起来合理,但也有它的缺点。当在一个紧密的循环中定期更新时,你可能会观察到比使用局部变量更差的性能,并且只有当对象是不可变的或者可以保证以正确的顺序进行读写时,读取共享对象的状态才是安全的。

您还可以使用结果交付BlockingQueue构建一些东西,一旦请求中断,计算线程就会将当前结果(甚至是对结果的定期更新)放入其中。

但最好的解决方案可能是(共享的) CompletableFuture。这是一种单一的结果项队列,但它具有更好的异常报告语义。

示例:

代码语言:javascript
复制
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,而不是中断线程。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37653733

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档