我需要使用 Java 多线程创建一个程序来计算常量 PI 的近似值。
我打算用格雷戈里-莱布尼茨级数计算 PI/4 的结果,然后乘以 4 得到 PI 近似值。
但是我对这个程序有些担心:
- 如何将计算过程分开,使程序实现多线程处理?因为公式是求和的,不知道怎么拆分,最后全部凑齐。
- 我在考虑程序将无限执行公式这一事实,因此用户需要提供一些配置执行的方法,以确定何时停止并返回结果。这可能吗?我该怎么做?
这是迄今为止我能做的最多的事情了。
public class PICalculate {
public static void main(String[] args) {
System.out.println(calculatePI(5000000) * 4);
}
static double calculatePI(int n) {
double result = 0.0;
if (n < 0) {
return 0.0;
}
for (int i = 0; i <= n; i++) {
result += Math.pow(-1, i) / ((2 * i) + 1);
}
return result;
}
}
最佳答案
最直接但不是最佳的方法是在您拥有的线程之间分配序列元素。即,如果您有 4 个线程,线程一将使用 n%4 == 0 个元素,线程 2 将使用 n%4 == 1 个元素,依此类推
public static void main(String ... args) throws InterruptedException {
int threadCount = 4;
int N = 100_000;
PiThread[] threads = new PiThread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new PiThread(threadCount, i, N);
threads[i].start();
}
for (int i = 0; i < threadCount; i++) {
threads[i].join();
}
double pi = 0;
for (int i = 0; i < threadCount; i++) {
pi += threads[i].getSum();
}
System.out.print("PI/4 = " + pi);
}
static class PiThread extends Thread {
private final int threadCount;
private final int threadRemainder;
private final int N;
private double sum = 0;
public PiThread(int threadCount, int threadRemainder, int n) {
this.threadCount = threadCount;
this.threadRemainder = threadRemainder;
N = n;
}
@Override
public void run() {
for (int i = 0; i <= N; i++) {
if (i % threadCount == threadRemainder) {
sum += Math.pow(-1, i) / (2 * i + 1);
}
}
}
public double getSum() {
return sum;
}
}
PiThread 更高效,但可以说更难阅读,如果循环更短:
public void run() {
for (int i = threadRemainder; i <= N; i += threadCount) {
sum += Math.pow(-1, i) / (2 * i + 1);
}
}
如果您不想按顺序和时间限制元素的数量,您可以遵循以下方法。但请注意,它仍然受限于 Long.MAX_VALUE,您必须使用 BigIntegers、BigDecimals 或任何其他合理的方法来改进它
public static volatile boolean running = true;
public static void main(String ... args) throws InterruptedException {
int threadCount = 4;
long timeoutMs = 5_000;
final AtomicLong counter = new AtomicLong(0);
PiThread[] threads = new PiThread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new PiThread(counter);
threads[i].start();
}
Thread.sleep(timeoutMs);
running = false;
for (int i = 0; i < threadCount; i++) {
threads[i].join();
}
double sum = 0;
for (int i = 0; i < threadCount; i++) {
sum += threads[i].getSum();
}
System.out.print("counter = " + counter.get());
System.out.print("PI = " + 4*sum);
}
static class PiThread extends Thread {
private AtomicLong counter;
private double sum = 0;
public PiThread(AtomicLong counter) {
this.counter = counter;
}
@Override
public void run() {
long i;
while (running && isValidCounter(i = counter.getAndAdd(1))) {
sum += Math.pow(-1, i) / (2 * i + 1);
}
}
private boolean isValidCounter(long value) {
return value >= 0 && value < Long.MAX_VALUE;
}
public double getSum() {
return sum;
}
}
关于java - Java中如何使用多线程编写圆周率计算程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41094056/