/* This class is for the purpose of computing the sum of the elements in a ** given array (or segment thereof) of integers. It uses threads so that ** the work is done (potentially, at least) in parallel. ** ** Author: R. McCloskey ** Date: May 9, 2023 */ public class ParallelArySummer implements Runnable { // class constant // -------------- private static final int LENGTH_THRESHOLD = 7; // instance variables // ------------------ private int[] a; // Array whose elements are to be summed private int low, high; // a[low..high) is the segment of the array // for which this object is responsible private int sum; // sum of the elements within a[low..high) // constructor // ----------- /* Establishes the array segment (namely, ary[low..high)) ** whose sum is to be computed by this object. ** pre: 0 <= low <= high <= a.length */ public ParallelArySummer(int[] ary, int low, int high) { this.a = ary; this.low = low; this.high = high; } /* Establishes that the array segment whose elements are to be summed ** by this object is the entire array. */ public ParallelArySummer(int[] ary) { this(ary, 0, ary.length); } // observers // --------- /* Returns the sum of the elements in a[low..high). */ public int sumOf() { return sum; } // run() method // ------------ public void run() { computeSum(); } /* Computes the sum of the elements in a[low..high) and assigns ** that value to the instance variable 'sum'. */ public void computeSum() { if (high - low <= LENGTH_THRESHOLD) { // Compute the sum of a short segment via a method that does // the calculations sequentially. this.sum = computeSumSequential(); // Report the result of this object's computation. reportSum("SHORT"); } else { // For a longer segment, use parallelism! // compute the index half way between low and high int mid = (low + high) / 2; // Create two threads using new objects of this class, one // responsible for finding the sum of the elements in a[low..mid) // and the other responsible for finding the sum of the elements // in a[mid..high). ParallelArySummer leftSummer = new ParallelArySummer(a, low, mid); ParallelArySummer rightSummer = new ParallelArySummer(a, mid, high); Thread leftThread = new Thread(leftSummer); Thread rightThread = new Thread(rightSummer); // start the two threads leftThread.start(); rightThread.start(); // wait for the two threads to terminate join(leftThread); join(rightThread); // The sum of the elements in a[low..high) is obtained by adding // together the sum of the elements in a[low..mid) and the sum // of the elements in a[mid..high). Place the result into the // instance variable. int leftSum = leftSummer.sumOf(); int rightSum = rightSummer.sumOf(); this.sum = leftSum + rightSum; // Report the result of this object's computation. reportSum("LONG"); } } /* Returns the sum of the elements in the array segment a[low..high). ** pre: 0 <= low <= high <= a.length */ private int computeSumSequential() { int sumSoFar = 0; for (int i = low; i != high; i++) { sumSoFar = sumSoFar + a[i]; } return sumSoFar; } /* Prints a message indicating the sum that was computed. */ private void reportSum(String remark) { System.out.printf("The sum of %s segment a[%d..%d) is %d\n", remark, low, high, sumOf()); } /* 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); } } }