Наиболее простой, но не самый оптимальный подход заключается в распределении элементов последовательности между потоками, которые у вас есть. То есть, если у вас есть 4 темы, нить один будет работать с п% 4 == 0 элементов, thread2 с п% 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;
}
}
, что ряд сходится очень медленно .... –
Я думаю, вы не очень хорошо разбираются в потоках, поэтому вернитесь и прочитайте учебники и изучите некоторые примеры. – gpasch
Одна из проблем с многопоточным подходом заключается в том, что для получения хорошего результата сначала нужно добавить небольшие термины из-за округления с плавающей запятой. Отметим также, что эта серия очень медленная, чтобы сходиться. – Bathsheba