// // Program to add numbers (read in from file, or generated // randomly). // // Command-line arguments: // (1) number of threads to use (P) // (2) name of file containing numbers (doubles) // or "-n N" to randomly generate N doubles. // // (This version is functionally identical to ThreadsSum1 // but is meant to be more Java-esque.) // import java.text.*; // has NumberFormat import java.util.*; // has Vector, Random // ---- Class containing main program -------------------------------- public class ThreadsSum2 { // ---- Member variables (for use by all threads) ---------------- private int P; // number of threads private double[] nums; // numbers to add // (count in nums.length) private double sum; // ---- Constructors --------------------------------------------- // Constructor for file input. public ThreadsSum2(int P, String fileName) { this.P = P; getFileInput(fileName); } // Constructor for randomly-generated input. public ThreadsSum2(int P, int n) { this.P = P; getRandomInput(n); } // ---- Method to do intended work ------------------------------- public void compute() { // Initialize. double startTime = Timer.elapsedSeconds(); sum = 0.0; // Create objects for threads. SumObj[] objs = new SumObj[P]; for (int i = 0; i < P; ++i) objs[i] = new SumObj(i); // Create threads, start them up, and wait for them to finish. ThreadManager tMgr = new ThreadManager(objs); tMgr.start(); tMgr.join(); // Print result. NumberFormat nf = NumberFormat.getInstance(); // set up to print "sum" in fixed-point // (not exponential) integer format. nf.setMaximumFractionDigits(4); System.out.println("Sum = " + nf.format(sum)); double endTime = Timer.elapsedSeconds(); System.out.println("Elapsed time (seconds) = " + Timer.format(endTime - startTime)); } // ---- Main program --------------------------------------------- public static void main(String[] args) { if (args.length < 2) { System.err.println("Usage: java ThreadsSum1 " + "numThreads [inputfile | -n N]"); System.exit(1); } int P = Integer.parseInt(args[0]); ThreadsSum2 obj; if (args.length == 2) obj = new ThreadsSum2(P, args[1]); else obj = new ThreadsSum2(P, Integer.parseInt(args[2])); obj.compute(); System.out.println("That's all, folks!"); } // ---- Helper methods ------------------------------------------- // Get input from file. private void getFileInput(String filename) { SimpleReader infile = null; try { infile = new SimpleReader(filename); } catch (SimpleReaderIOException e) { System.err.println("Input file " + filename + " not found"); System.exit(1); } Vector vTemp = new Vector(); try { while (true) // loop ends on EOF exception vTemp.add(new Double(infile.readDouble())); } catch (SimpleReaderIOException e) { } nums = new double[vTemp.size()]; for (int i = 0; i < nums.length; ++i) nums[i] = ((Double) vTemp.elementAt(i)).doubleValue(); } // Generate (pseudo)random input. // Uses the same seed every time so answer does not depend on number // of threads. private void getRandomInput(int n) { nums = new double[n]; Random generator = new Random(1); for (int i = 0; i < nums.length; ++i) nums[i] = generator.nextDouble(); } // ---- Methods for use by threads ------------------------------- // Add partial sum to global sum. // Note use of "synchronized" keyword to ensure that only one // thread at a time can access this shared variable. private synchronized void addToSum(double d) { // System.out.println("partial sum = " + d); sum += d; } // ---- Inner class to contain data and code for each thread ----- class SumObj implements Runnable { private int id; public SumObj(int id) { this.id = id; } // Generally, run() defines behavior of thread. // Here, it computes the partial sum of N/P of the elements // and adds it to the sum. public void run() { double partialSum = 0.0; int N = nums.length; int numsPerThread = (N + P - 1) / P; int first = id * numsPerThread; int limit = first + numsPerThread; if (limit > N) limit = N; for (int i = first; i < limit; ++i) partialSum += nums[i]; addToSum(partialSum); } } }