I have to write a code to use multithreading for piEstimator. It is a simple algorithm that makes an estimate of Pi. The algorithm works by throwing theoretical darts at a dartboard darts that hit the board fall within the quarter circle darts that miss is outside it. The dartboard has a height and width of 1. We throw a dart by generating a random x and y coordinate for the dart between 0 and 1. I have calculated this using Pythagoras (x2+y2= dist2)
my code
import java.util.Random;
public class PiEstimator {
//number of iterations the algorithm, a larger number here should result in a more accurate estimate
public static int numberOfDarts = 100_000_000;
public static void main(String[] args) {
//how many darts lie within the quarter circle region
int within = 0;
Random r = new Random();
for(int i = 0; i< numberOfDarts; i++){
//get x and y coordinates for the darts
double x = r.nextDouble();
double y = r.nextDouble();
//calculate the distance from the origin (0, 0) darts with a distance less than 1 are within the
//quarter circle so add these to within
double dist = Math.sqrt((x*x) + (y*y));
if(dist < 1)
within++;
}
//estimate pi by getting proportion of darts in the quarter circle and multiplying by 4.
double estimate = (double)within/numberOfDarts *4;
System.out.println(estimate);
}
}
What I want to do is
Every time 2 separate threads need to synchronize anything, you get a slowdown. Hence, trying to keep one counter that counts how many darts were thrown by all the threads is quite expensive, and doesn't seem relevant: It is much less tricky to gather up individual thread's total throw counts when they are done, or if you intent is to run them endlessly, for them to update the 'main counter' only every 1000 throws or so.
The primitives you need to perform this task:
You start with encapsulating the 'job' of a dart thrower. Whatever state you want to look at is probably best stored as actual state - as fields of instances of such a class. You're going to make a bunch of these, and have one thread running each.
public class DartThrower implements Runnable {
private int within;
private int thrown;
@Override public void run() {
Random r = new Random();
for (int i = 0; i < MAX_THROW; i++) {
// the usual logic goes here
}
}
}
Then to actually make a thread that runs a 'thrower' on its own, simply:
DartThrower thrower = new DartThrower();
new Thread(thrower).start();
Anytime a thread accesses any field in any class anywhere, the JVM flips an evil coin. If the coin lands heads, you get a local cached copy of that field (unique to the thread - one thread reads '5', another may read '8', because they each have a local copy). On tails, the thread syncs up the cached copies with other threads.
It's 'evil' in the sense that it may flip heads every time, reliably, throughout all your testing and your first week on production, and then it starts flipping tails juuust when that important prospective customer shows up and you're giving a demo. The name of the game is to prevent the JVM from flipping it. You do this by establishing happens-before relationships, which is quite detailed - usually you want ALL inter-thread communication to be tightly controlled, because you can't test this stuff.
In this case, AtomicInteger
is great. You can use it to have a single counter that all the dart instances increment. That class promises syncing (but, all syncing is somewhat slow, so keep that in mind).
To speed things up, you can have your dart throwers update the 2 AtomicIntegers representing thrown and within for all throwers, only every 1000 throws or so, this should massively speed things up considerably.
Alternatively, don't have any global AtomicIntegers at all; just run your dart throwers and wait for them to complete the job. "The thread is now done" is guaranteed to happens-before any attempt to read anything that the now-done thread changed by any code that already established that the other thread is done. Thread itself isn't the right abstraction for this - for that you need an ExecutorPool.
This concept of "I have a task I want to do a few million times, each 'run' is independent of all others, and I just want to merge some 'result' values from each runner once they are all done, then all I need is the merged results" - is very common. ExecutorPool is a class baked into core java that helps with this.
This is by far the best option if you want to go for maximum speed: Set up X dart throwers (X = equal to # of cores on the CPU and figured out by the JVM for you), they all throw however many they need to, and you only report the result at the end.