问题描述
我一直在尝试使用 Monte Carlo 模拟并行计算 pi 的值。
到目前为止,我已经创建了线程,并生成了随机点,但是我无法将这些生成的点从线程返回到主线程。
如何解决这个问题?
下面是我写的代码
import java.util.*;
class MyThread extends Thread{
int points;
int insidePoints;
public MyThread(int insidePoints,int points){
this.points = points;
this.insidePoints = insidePoints;
}
// simulating monte carlo to generate points and check which are inside the circle
public void run(){
int prec = 1000000;
Random rand = new Random();
for( int i=0 ; i < points ; ++i){
double x = (double)rand.nextInt(prec+1)/(double)prec;
double y = (double)rand.nextInt(prec+1)/(double)prec;
if( (x*x + y*y) <= 1){
++insidePoints;
}
}
System.out.println("Thread " + Thread.currentThread().getId() + " running and Inside points are" + insidePoints);
}
public int getCount(){
return this.insidePoints;
}
}
public class A{
public static void main(String[] args){
int totalPoints = 1000000;
int insidePoints = 0;
int threadsToBeUsed = 1;
Scanner scan = new Scanner(system.in);
System.out.println("Enter the value of Threads : ");
threadsToBeUsed = scan.nextInt();
try{
int eachThreadPoints = totalPoints/threadsToBeUsed;
Thread[] thread = new Thread[threadsToBeUsed];
for(int i = 0; i < threadsToBeUsed ; ++i){
if( i == (threadsToBeUsed-1)){
eachThreadPoints += (totalPoints)%eachThreadPoints ;
}
MyThread myT = new MyThread(insidePoints,eachThreadPoints);
thread[i] = new Thread(myT);
thread[i].start();
}
for( int i=0; i < threadsToBeUsed; ++i)
thread[i].join();
System.out.println("Number of inside points :" + insidePoints);
System.out.println("Pi/4 = " + (double)insidePoints/(double)totalPoints);
System.out.println("Pi = " + 4*(double)insidePoints/(double)totalPoints);
} catch(Exception e){
System.out.println(e);
System.exit(1);
}
}
}
解决方法
作为一种替代方法,您可以使用 Java Executor Interface,它提供了比显式处理线程更高级的抽象。此外,您可以考虑使用 ThreadLocalRandom:
一个与当前线程隔离的随机数生成器。就像 Math 类使用的全局随机生成器,一个 ThreadLocalRandom 是 用内部生成的种子初始化,否则可能不会 在适用的情况下,使用 ThreadLocalRandom 而不是 并发程序中的共享随机对象通常会遇到 少得多的开销和争用。 ThreadLocalRandom 的使用是 尤其适用于多项任务(例如,每个任务 ForkJoinTask) 在线程池中并行使用随机数。
回到你的问题:
但我无法将这些生成的点从线程返回到 主要功能。
您可以利用 Executor
接口并提交返回 Java Future 的任务:
Future 表示异步计算的结果。方法 提供检查计算是否完成,等待其 完成,并检索计算结果。结果 只能在计算完成时使用方法 get 检索 完成,必要时阻塞,直到它准备好。
每个线程计算内部的点数,并返回该值作为主线程的Future。 主线程依次对其他线程返回的所有值求和。
在代码方面,我们会创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(threadsToBeUsed);
然后是一个收集结果的列表
List<Future<Integer>> results = new ArrayList<>(threadsToBeUsed);
然后提交并行完成的工作
for(int i = 0; i < threadsToBeUsed; i++){
Future<Integer> insidePointsThr = pool.submit(new task(eachThreadPoints));
results.add(insidePointsThr);
}
让 main 线程对其他线程的所有结果求和:
int insidePoints = results.stream().mapToInt(f -> f.get()).sum();
打印结果,并关闭线程池:
pool.shutdown();
运行代码示例(基于您提供的代码):
import java.util.*;
import java.util.concurrent.*;
class task implements Callable<Integer> {
final int points;
public task(int points){
this.points = points;
}
@Override
public Integer call() {
int insidePoints = 0;
int prec = 1000000;
for( int i=0 ; i < points ; ++i){
double x = (double)ThreadLocalRandom.current().nextInt(prec + 1)/(double)prec;
double y = (double)ThreadLocalRandom.current().nextInt(prec + 1)/(double)prec;
if( (x*x + y*y) <= 1){
++insidePoints;
}
}
System.out.println("Thread " + Thread.currentThread().getId() + " running and Inside points are " + insidePoints);
return insidePoints;
}
}
class A{
public static void main(String[] args){
int totalPoints = 1000000;
Scanner scan = new Scanner(System.in);
System.out.println("Enter the value of Threads : ");
int threadsToBeUsed = scan.nextInt();
int eachThreadPoints = totalPoints/threadsToBeUsed;
ExecutorService pool = Executors.newFixedThreadPool(threadsToBeUsed);
List<Future<Integer>> results = new ArrayList<>(threadsToBeUsed);
for(int i = 0; i < threadsToBeUsed; i++){
Future<Integer> insidePointsThr = pool.submit(new task(eachThreadPoints));
results.add(insidePointsThr);
}
int insidePoints = results.stream().mapToInt(A::getFutureResult).sum();
System.out.println("Number of inside points :" + insidePoints);
System.out.println("Pi/4 = " + (double)insidePoints/(double)totalPoints);
System.out.println("Pi = " + 4*(double)insidePoints/(double)totalPoints);
pool.shutdown();
}
private static int getFutureResult(Future<Integer> f) {
try {
return f.get();
} catch (InterruptedException | ExecutionException e) {
// handle the error
}
return 0;
}
}
输出(4 个线程):
Enter the value of Threads :
4
Thread 16 running and Inside points are 196447
Thread 17 running and Inside points are 196147
Thread 15 running and Inside points are 196076
Thread 14 running and Inside points are 196795
Number of inside points :785465
Pi/4 = 0.785465
Pi = 3.14186