import java.util.List; /** * Generic example of master/worker program. * "Tasks" just consist of sleeping for a specified time; times to wait are * generatedly randomly from 1 to a specified maximum. * * Command-line arguments: total tasks, maximum task time, number of threads, * (optional) "--verbose" for verbose output * * Parallel version with dynamic assignment of tasks to threads. */ public class MasterWorkerParDynamic { /* variables to be used by all threads */ private int numThreads; private TaskQueue taskQueue; private boolean verbose = false; private int totalTaskTime = 0; private int minThreadTotalTaskTime; private int maxThreadTotalTaskTime; /** * Main method. */ public static void main(String[] args) { String usageMessage = "parameters: numTasks maxTaskTime numThreads [--verbose]"; final int REQUIRED_PARMS = 3; int numTasks = 0; int maxTaskTime = 0; int numThreads = 0; boolean verbose = false; /* process command-line arguments */ if (args.length < REQUIRED_PARMS) { System.err.println(usageMessage); System.exit(1); } try { numTasks = Integer.parseInt(args[0]); maxTaskTime = Integer.parseInt(args[1]); numThreads = Integer.parseInt(args[2]); } catch (NumberFormatException e) { System.err.println(usageMessage); System.exit(1); } if (args.length > REQUIRED_PARMS) { if (args[REQUIRED_PARMS].equals("--verbose")) verbose = true; else { System.err.println(usageMessage); System.exit(1); } } /* do processing */ new MasterWorkerParDynamic(numTasks, maxTaskTime, numThreads, verbose); } /** Constructor (actually where processing occurs too). */ public MasterWorkerParDynamic(int numTasks, int maxTaskTime, int _numThreads, boolean _verbose) { numThreads = _numThreads; verbose = _verbose; maxThreadTotalTaskTime = 0; minThreadTotalTaskTime = maxTaskTime * numTasks; /* start timing */ long startTime = System.currentTimeMillis(); /* build queue of tasks */ taskQueue = new TaskQueue(numTasks, maxTaskTime); /* create threads */ Thread[] threads = new Thread[numThreads]; for (int i = 0; i < threads.length; ++i) { threads[i] = new Thread(new Worker(i)); } /* start them up */ for (int i = 0; i < threads.length; ++i) { threads[i].start(); } /* wait for them to finish */ for (int i = 0; i < threads.length; ++i) { try { threads[i].join(); } catch (InterruptedException e) { System.err.println("this should not happen"); e.printStackTrace(); } } /* end timing and print result */ long endTime = System.currentTimeMillis(); System.out.printf("\nthreaded parallel version with %d threads" + ", dynamic assignment of tasks\n", numThreads); System.out.printf("number of tasks = %d\n", numTasks); System.out.printf("max task time = %d\n", maxTaskTime); System.out.printf("total task time = %d\n", totalTaskTime); System.out.printf("total task time in threads ranges from %d to %d\n", minThreadTotalTaskTime, maxThreadTotalTaskTime); System.out.printf("running time = %g\n", (double) (endTime - startTime) / 1000); } /* methods for use by threads */ /** * Update global variables at end of thread. */ private synchronized void updateGlobals(int threadTotalTaskTime) { maxThreadTotalTaskTime = Math.max(maxThreadTotalTaskTime, threadTotalTaskTime); minThreadTotalTaskTime = Math.min(minThreadTotalTaskTime, threadTotalTaskTime); totalTaskTime += threadTotalTaskTime; } /** * Class to contain code to run in each thread. */ private class Worker implements Runnable { private int myID; private int threadNumTasks = 0; private int threadTotalTaskTime = 0; public Worker(int ID) { myID = ID; } public void run() { FakeTasks.Task t = null; /* get tasks from queue until queue is empty */ while ((t = taskQueue.get()) != null) { ++threadNumTasks; threadTotalTaskTime += t.time; FakeTasks.TaskResult tr = t.execute(); if (verbose) { System.out.printf("(thread %d) %s\n", myID, FakeTasks.toString(t, tr)); } } System.out.printf( "thread %d number of tasks = %d, total task time = %d\n", myID, threadNumTasks, threadTotalTaskTime); /* thread-safe update to globals */ updateGlobals(threadTotalTaskTime); } } /** * Class for task queue (thread-safe). */ private static class TaskQueue { private List tasks; public TaskQueue(int numTasks, int maxTaskTime) { tasks = FakeTasks.randomTasks(numTasks, maxTaskTime); } /** Get a task (returns null if queue is empty). */ public synchronized FakeTasks.Task get() { if (tasks.isEmpty()) { return null; } else { return tasks.remove(0); } } } }