用Java计算PI。错误值
我试图使用Gregory-Leibniz
算法来计算PI,但我总是只使用多线程来得到错误的值。单线程工作正常
我认为问题在于共享的k
值,计算混乱
错误的PI值:
Select an option: 4 How many points? 100000 How many threads? 32 Concurrent Gregory-Leibniz estimated PI value : 2.7663972054374577. Executed in 121.578657 ms.
需要帮忙吗
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* The Class GregoryLeibniz.
*/
public class GregoryLeibniz {
/** The in circle. */
private double factor;
/** The sum. */
private double sum;
/** The points. */
private long points;
/** The n processors. */
private int nProcessors;
private long k;
/**
* Instantiates a new gregory leibniz.
*
* @param points the points
* @param nProcessors the n processors
*/
public GregoryLeibniz(long points, int nProcessors) {
super();
this.points = points;
this.nProcessors = nProcessors;
}
/**
* The Class GregoryLeibnizImpl.
*/
public class GregoryLeibnizImpl implements Runnable {
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if(k % 2 == 0) factor = 1.0;
else factor = -1.0;
sum += factor / (2*k +1);
}
}
/**
* Calculate PI.
*
* @return the double
*/
public double calculatePI() {
ExecutorService executor = Executors.newWorkStealingPool(nProcessors);
for (k = 0; k < points; k++) {
Runnable worker = new GregoryLeibnizImpl();
executor.execute(worker);
}
executor.shutdown();
while(!executor.isTerminated()) { }
return 4.0 * sum;
}
}
# 1 楼答案
尝试同步运行方法。如果你让k没有互斥,一个线程将检查k的模,设置因子,然后它将进入睡眠状态,下一个线程将检查模集(相同)因子,执行sum+=填充,然后进入睡眠状态。在那之后,第一个线程还将使用旧因子进行sum+=运算
# 2 楼答案
你需要给你的员工一份
k
。除此之外,让员工只做一步,并不能真正赢得很多。创建的工作线程不应超过可用的CPU(核心),并为每个工作线程分配一部分可计算的总数还请注意,这仍然会给您留下一个错误的
sum
,因为如果两个工作人员同时对其进行读写,其中一个结果将丢失让每个工作人员维护一个私有
sum
,然后在完成所有操作后,在主线程中将它们的私有总和相加比如:
然后将循环更改为以下内容:
您需要将这些worker实例保存在某个位置,例如一个列表,以便在完成后收集它们的结果
# 3 楼答案
GregoryLibNizimpl的每个实例都需要独立运行。或者你需要一个互斥。或者两者兼而有之
GregoryLibNizimpl需要将“k”作为构造函数参数,并将其存储为成员变量
在
sum
周围需要一个互斥/保护。否则,需要在calculatePI
函数末尾“汇总”工作线程对象的所有结果这一行:
会烧掉整个内核并破坏代码的性能。改用awaitTermination方法
更新
我需要一些实践,所以我重组了你的代码,以获得一个有价值的解决方案。也许我能帮忙