DEMO CODE FROM CSC543 JANUARY 20, 2021. IT IS ALSO AVAILABLE ON mcgonagall or acad IN /home/kutztown.edu/parson/multip/demo1spring2021. THE CODE: ********************************************************* // GarbledOutput.java D. Parson January 2021 introductory example code // showing the basic Java multithreading approach for CSC543 class 1. import java.util.concurrent.CountDownLatch ; // CountDownLatch acts like the gate in a horse race. // All the threads must countDown() and await() the latch before // they are all released concurrently to run. The following two imports are // for writing to an output file. import java.io.File ; import java.io.PrintWriter ; // Main class: public class GarbledOutput { // Helper class Threader is an active class, where each such object is // intended to run a thread of execution (a.k.a. instruction stream) // in its run() method. java.lang.Runnable is just an interface declaring // that any subclass must supply the public run() method. public static class Threader implements java.lang.Runnable { // Use private whenever possible to hide data. // Use final whenever possible to guarantee no mutation. // Use volatile *only as necessary* to ensure mutable built-in // data types get initialized & updated so other threads can see // the updates. The thread that runs run() is different than the main // thread that calls the Threader constructor. However in this case, // start() never starts run()'s thread until after this object is // constructed, and start() implements a memory barrier in the Java // Memory Model (we will discuss), so counter need not be volatile. // Volatile variables get flushed to main memory on every update, // and read into registers repeatedly, incurring overhead. // Volatile is not needed here because start() comes between // construction and run(). private int counter = 0 ; private final PrintWriter writer ; private final CountDownLatch mylatch ; public Threader(PrintWriter writer, CountDownLatch mylatch) { this.writer = writer ; this.mylatch = mylatch ; } public void run() { // System.err.println("START THREAD " // + Thread.currentThread().getId()); // System.err.flush(); // I leave debugging prints commented until I no longer need them. try { // The CountDownLatch is a demo kludge just to force the run() // threads to indeed run concurrently. mylatch.countDown(); // Decrement count at the "starting gate" mylatch.await(); // Wait for all the threads before proceeding. } catch (InterruptedException xxx) { // Blocking calls like await() may throw InterruptedException // if they receive an interrupt signal from another thread in // the same process, usually as a signal to initiate worker // thread termination. This demo is not using interrupts, // but the compiler still forces a catch due to await(). } // Without some form of synchronization, the threads will // intermix their output. synchronized(writer) uses the lock // built into the writer object -- every Java object has a // built-in lock -- to serialize execution of the following // block of code, where "serialize" means one-thread-at-a-time // execution. synchronized methods and blocks are Java's // implementation of the "monitor" concept. All threads must // synchronize on the same object-lock. synchronized(writer) { while (++counter < 20) { writer.println("" + counter + " " + Thread.currentThread().getId()); } } } } public static void main (String [] args) { // Make a practice of hiding any variable you can as a // local variable or function parameter. That way it is accessible // only within the thread running that function. Each thread // gets its own set of local variables & parameters. // Note, though, that local variables may point to shared objects, // which is the case here. We will discuss how "final" variables, // similar to C++ "const", enhance thread safety by disallowing // mutation of such variables by sharing threads. final int numthreads = 10 ; PrintWriter Gwriter = null ; CountDownLatch latch = null ; try { Gwriter = new PrintWriter("junk.txt"); // demo output latch = new CountDownLatch(numthreads); Thread [] runners = new Thread [ numthreads ]; // First loop builds the active Threader objects. for (int i = 0 ; i < runners.length ; i++) { // Threader is an active object whose run() method // runs its thread. The java.lang.Thread object wrapped // around it initiates and manages the thread. runners[i] = new Thread(new Threader(Gwriter, latch)); } // Second loop starts threads running in their run() methods. // start() implements a memory barrier -- To Be Defined. for (int i = 0 ; i < runners.length ; i++) { runners[i].start(); } // In the third loop the main thread -- this thread -- waits // for them to terminate when their run() activations return. // join() implements a memory barrier -- To Be Defined. for (int i = 0 ; i < runners.length ; i++) { try { runners[i].join(); } catch (InterruptedException iex) { // Impossible if not sent from another thread. } } } catch (java.io.FileNotFoundException fxx) { // new PrintWriter declares it may throw this exception. System.err.println("ERROR, FILE NOT FOUND " + fxx); } finally { // finally runs regardless of whether exceptions thrown or not. if (Gwriter != null) { // If file opened OK. Gwriter.close(); // Flush output buffer to output file. } } } } ********************************************************* TO COMPILE & RUN, CREATING junk.txt: javac GarbledOutput.java CLASSPATH=. java GarbledOutput less junk.txt ********************************************************* A SAMPLE junk.txt OUTPUT WITH THE synchronized BLOCK. THE VALUES ARE VARIABLE counter, THEN THE INTERNAL THREAD ID: 1 30 2 30 3 30 4 30 5 30 6 30 7 30 8 30 9 30 10 30 11 30 12 30 13 30 14 30 15 30 16 30 17 30 18 30 19 30 1 29 2 29 3 29 4 29 5 29 6 29 7 29 8 29 9 29 10 29 11 29 12 29 13 29 14 29 15 29 16 29 17 29 18 29 19 29 1 28 2 28 3 28 4 28 5 28 6 28 7 28 8 28 9 28 10 28 11 28 12 28 13 28 14 28 15 28 16 28 17 28 18 28 19 28 1 27 2 27 3 27 4 27 5 27 6 27 7 27 8 27 9 27 10 27 11 27 12 27 13 27 14 27 15 27 16 27 17 27 18 27 19 27 1 26 2 26 3 26 4 26 5 26 6 26 7 26 8 26 9 26 10 26 11 26 12 26 13 26 14 26 15 26 16 26 17 26 18 26 19 26 1 25 2 25 3 25 4 25 5 25 6 25 7 25 8 25 9 25 10 25 11 25 12 25 13 25 14 25 15 25 16 25 17 25 18 25 19 25 1 24 2 24 3 24 4 24 5 24 6 24 7 24 8 24 9 24 10 24 11 24 12 24 13 24 14 24 15 24 16 24 17 24 18 24 19 24 1 22 2 22 3 22 4 22 5 22 6 22 7 22 8 22 9 22 10 22 11 22 12 22 13 22 14 22 15 22 16 22 17 22 18 22 19 22 1 21 2 21 3 21 4 21 5 21 6 21 7 21 8 21 9 21 10 21 11 21 12 21 13 21 14 21 15 21 16 21 17 21 18 21 19 21 1 23 2 23 3 23 4 23 5 23 6 23 7 23 8 23 9 23 10 23 11 23 12 23 13 23 14 23 15 23 16 23 17 23 18 23 19 23 ********************************************************* A SAMPLE junk.txt OUTPUT WITHOUT THE synchronized BLOCK: 1 27 1 22 1 23 2 27 2 22 3 27 2 23 4 27 3 22 5 27 3 23 4 22 6 27 5 22 7 27 1 25 6 22 8 27 2 25 7 22 9 27 3 25 8 22 10 27 4 25 9 22 11 27 5 25 10 22 12 27 6 25 11 22 13 27 7 25 12 22 14 27 8 25 13 22 15 27 9 25 14 22 16 27 10 25 17 27 15 22 18 27 16 22 19 27 17 22 18 22 19 22 4 23 1 29 5 23 6 23 2 29 7 23 3 29 8 23 4 29 9 23 5 29 10 23 6 29 11 23 7 29 12 23 8 29 13 23 9 29 14 23 10 29 15 23 11 29 16 23 12 29 17 23 13 29 18 23 14 29 19 23 15 29 16 29 1 21 17 29 2 21 1 26 18 29 3 21 2 26 19 29 1 30 3 26 2 30 3 30 4 26 4 30 1 24 5 26 5 30 2 24 6 26 3 24 7 26 6 30 8 26 4 24 9 26 7 30 5 24 10 26 6 24 8 30 11 26 9 30 12 26 13 26 4 21 10 30 14 26 5 21 11 30 6 21 11 25 7 21 12 30 12 25 8 21 13 25 13 30 9 21 14 30 10 21 11 21 1 28 15 30 12 21 2 28 16 30 3 28 17 30 13 21 4 28 18 30 14 21 5 28 19 30 15 21 6 28 16 21 17 21 7 28 18 21 14 25 19 21 8 28 15 25 9 28 10 28 16 25 11 28 17 25 15 26 12 28 18 25 16 26 13 28 19 25 17 26 14 28 18 26 15 28 19 26 16 28 17 28 7 24 18 28 8 24 19 28 9 24 10 24 11 24 12 24 13 24 14 24 15 24 16 24 17 24 18 24 19 24 *********************************************************