import java.util.Arrays; // for testing purposes only import java.util.Scanner; // for testing purposes only /* This class has a method that computes the sum of the elements of a given ** array of integers. It uses threads so that the work is done (potentially, ** at least) in parallel. ** ** Author: R. McCloskey ** Date: May 13, 2021 */ public class ArySummerParSimpler implements Runnable { // class constant // -------------- private static final int LENGTH_THRESHOLD = 7; // instance variables // ------------------ private int[] a; // Array whose elements are "summed". private int low, high; // Calling run() on this object results in the sum private int sum; // of the elements in a[low..high) being stored in // instance variable 'sum'. // constructor // ----------- /* Establishes the array segment whose elements are to be summed by ** this object (namely, ary[low..high)). ** pre: 0 <= low <= high <= a.length */ public ArySummerParSimpler(int[] ary, int low, int high) { this.a = ary; this.low = low; this.high = high; } /* Establishes that all the elements of the given array are to be ** summed by this object. */ public ArySummerParSimpler(int[] ary) { this(ary, 0, ary.length); } // observer // -------- /* Returns the sum of the elements of the array segment that this ** object is responsible for. */ public int sumOf() { return sum; } // run() method // ------------ public void run() { sum = computeSum(); } /* Computes the sum of the elements in a[low..high), placing that ** sum in the instance variable 'sum' and also returning it. */ public int computeSum() { if (high - low <= LENGTH_THRESHOLD) { // Sum the values in a short segment using a sequential algorithm. sum = sumOfSeq(); System.out.printf("Sum of elements in SHORT range [%d..%d) is %d\n", low, high, sum); } else { // For a longer segment, use parallelism! int mid = (low + high) / 2; ArySummerParSimpler leftASPS = new ArySummerParSimpler(a,low,mid); ArySummerParSimpler rightASPS = new ArySummerParSimpler(a,mid,high); Thread leftThread = new Thread(leftASPS); leftThread.start(); //Thread rightThread = new Thread(rightASPS); //rightThread.start(); //join(rightThread); // -------------------------------------------------------------- // As an alternative to the three lines above (which uses a new // thread 'rightThread' to compute the sum of the elements in // a[mid..high)), could instead have used 'this' thread by directly // making the call rightASPS.computeSum(); // -------------------------------------------------------------- rightASPS.computeSum(); join(leftThread); sum = leftASPS.sumOf() + rightASPS.sumOf(); System.out.printf("Sum of elements in range [%d..%d) is %d\n", low, high, sum); } return sum; } /* Computes the sum of the elements in a[low..high) sequentially and ** places the result in the instance variable 'sum'. ** pre: 0 <= low <= high <= a.length */ private int sumOfSeq() { int sumSoFar = 0; for (int i = low; i != high; i++) { sumSoFar = sumSoFar + a[i]; } return sumSoFar; } /* Applies join() to the given thread, catching InterruptedException ** if it is thrown. */ private void join(Thread t) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(System.out); } } // main() method (for testing purposes) // ------------------------------------ public static void main(String[] args) { Scanner keyboard = new Scanner(System.in); int aryLen = getIntInput(keyboard, "Enter array length: "); int lowBound = getIntInput(keyboard, "Enter lower bound value: "); int upperBound = getIntInput(keyboard, "Enter upper bound value: "); int seed = getIntInput(keyboard, "Enter random seed: "); RandIntArrayMaker riam = new RandIntArrayMaker(); // Make an array filled with random integers in accord with // parameters entered by user. int[] ary = riam.randomIntArray(aryLen, lowBound, upperBound, seed); // new int[] { 3, -7, 15, 2, 5, 18, -9, -1, 4, 12, -17, 2, // 19, 31, -7, 8, 0, 4, 16, -11, -2, 9, 6 }; System.out.printf("Array: %s\n", Arrays.toString(ary)); ArySummerParSimpler asps = new ArySummerParSimpler(ary); System.out.println("Adding..."); //int sum = asps.computeSum(); asps.computeSum(); int sum = asps.sumOf(); System.out.printf("Sum is %d\n", sum); int sumUsingSeq = sumOfSequential(ary, 0, ary.length); if (sum != sumUsingSeq) { System.out.printf("Oops; seq. alg. yields %d\n", sumUsingSeq); } } /* Returns the sum of the elements in the given array segment, ** ary[low..high), using the obvious sequential algorithm. ** Used for testing purposes. (Can the sumOfSeq() method inside ** the nested class be used instead? Should that method be moved ** so that it is not inside the nested class?) */ private static int sumOfSequential(int[] ary, int low, int high) { int sumSoFar = 0; for (int i = low; i != high; i++) { sumSoFar = sumSoFar + ary[i]; } return sumSoFar; } /* Displays the specified prompt and then returns the response read ** from the specified Scanner (which is assumed to be in a form that ** can be interpreted as an integer). */ private static int getIntInput(Scanner scanner, String prompt) { System.out.print(prompt); return scanner.nextInt(); } }