We will divide the work of computing the sum of all values in an array over multiple threads. Each thread will compute the sum of a subrange and then update a shared sum variable and a shared count of completed threads.

Since the shared variable is updated by multiple threads, we need to ensure that the updates do not interfere with each other. Your task is to use a lock so that only one thread at a time updates the shared data. Note that you should not use a lock to control access to the array which is not mutated. Otherwise we would completely lose the benefit of using multiple threads.

Note: We use a slightly wasteful mechanism for finding out when all threads have completed their work. Several exercises in this chapter explore other strategies.

Complete the following file:

DataSet.java

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class DataSet { /** Constructs an empty data set. */ public DataSet(double[] values) { sum = 0; this.values = values; myLock = new ReentrantLock(); } private class RangeProcessor implements Runnable { public RangeProcessor(int start, int end) { this.start = start; this.end = Math.min(end, values.length); } public void run() { // TODO: use lock to protect access to shared mutated variables double total = 0; for (int i = start; i < end; i++) total += values[i]; sum += total; completionCount++; } private int start; private int end; } /** Gets the average of the added data. @return the average or 0 if no data has been added */ public double getAverage() { if (values.length == 0) return 0; final int THREADS = 10; int size = values.length / THREADS; for (int i = 0; i < THREADS; i++) { Runnable r = new RangeProcessor(i * size, (i + 1) * size); Thread t = new Thread(r); t.start(); } // busy waiting is not an optimal solution final int DELAY = 100; try { while (completionCount < THREADS) { Thread.sleep(DELAY); } } catch (InterruptedException ex) { return 0; } return sum / values.length; } private double[] values; private double sum; private int completionCount; private Lock myLock; // this method is used to check your work public static void main(String[] args) { final int SIZE = 10000000; double[] v = new double[SIZE]; for (int i = 0; i < SIZE; i++) v[i] = i; DataSet data = new DataSet(v); double avg = data.getAverage(); System.out.println(avg); } }