Concurrent & Distributed Computing PRACTICAL 3 – Java Threads Question 1 – Introducing Java Threads There are two different ways of creating a thread. First way to create a thread Create a new subclass of the Thread class and override the run method, for example: class SimpleThread1 extends Thread { public void run() { for ( int count = 0; count < 4; count++) System.out.println( "Message " + count + "From: " + getName() ); } } A SimpleThread1 object(i.e. parallel) can now be created and started running (using parallel.start()) to run in parallel with the main method thread itself. class TestThread1 { public static void main( String[] args ) { SimpleThread1 parallel = new SimpleThread1(); System.out.println( "Create the thread"); parallel.start(); System.out.println( "Started the thread" ); System.out.println( "End" ); } } (a) Create the SimpleThread1 class and use it in the TestThread1 class. Observe the output and verify its correctness. Second way to create a thread The second way of creating threads is to implement the Runnable interface (provided by Java) in a class and then an object of this class can be made into a thread (by passing it to the constructor of the Thread class). The resulting thread can then be started and it’s run() method will execute. For example: class PossibleThread2 implements Runnable { public void run() { for ( int count = 0; count < 4; count++) System.out.println( "Message " + count + " From: " + Thread.currentThread().getName() ); } } Now consider a main program that instantiates a Runnable object (i.e. notAThread) and passes it as a parameter to the constructer of the Thread class. The thread object (i.e. parallelThread) can now be started. 1 class TestThread2 { public static void main( String[] args ) { PossibleThread2 notAThread = new PossibleThread2(); Thread parallelThread = new Thread( notAThread ); System.out.println( "Create the thread"); parallelThread.start(); System.out.println( "Started the thread" ); System.out.println( "End" ); } } (b) Create the PossibleThread2 class and use it in the TestThread2 class. Observe the output and verify its correctness. Question 2 – Giving a thread a Name When you create a thread you have the option of giving it a textual name, which is passed as a parameter when you create it. Example of Thread Use Run the program RunThreads.java. This program creates two instances of the ShowlineThread class. /* RunThreads.java */ class RunThreads { public static void main(String args[]) { Showline possibleThread = new Showline(); //create object that can become a thread Thread t1 = new Thread ( possibleThread, "Kate" ); // call thread constructor to make thread Thread t2 = new Thread ( possibleThread, "John" ); // call thread constructor to make thread t1.start(); // start thread t2.start(); // start thread } } /* Showline.java */ public class Showline implements Runnable { public void run() { while (true) System.out.println(Thread.currentThread().getName()); // gets current threads name and print it } (a) Verify that the output is as expected. (b) Introduce two more threads called “Mary” and “Peter” and run them concurrently with the existing threads. 2 Question 3 – Sleeping Threads Now look at the three classes: RunIdlers.java, Idler.java, and CDS.java (below). RunIdlers creates two Idler objects: Idler lover = new Idler(8000); Idler hater = new Idler(16000); The numbers 8000 and 16000 are millisecond lengths (8 seconds, and 16 seconds). Look at the constructor method for the Idler object. The millisecond lengths are copied to a private variable, private_idle, inside the Idler object. Consider the creation of the threads in main. These two lines kick-off the run() method in the Idler objects. new Thread(lover, "She loves me").start(); new Thread(hater, "No, she hates me").start(); The run() method contains an infinite loop. The thread prints out its name then sleeps for the number of milliseconds prescribed by its private variable. Finally, look at the idle() method in the class CDS.java. It causes the currently executing thread to sleep for a certain number of milliseconds and prints out the name of the thread before it sleeps and when it wakes up. class RunIdlers { public static void main(String args[]) { Idler lover = new Idler(8000); Idler hater = new Idler(16000); new Thread(lover, "She loves me").start(); new Thread(hater, "No, she hates me").start(); } } public class Idler implements Runnable { private int private_idle; Idler (int idleTime) // constructer { private_idle = idleTime; } public void run() { while (true) { System.out.println(“Current Thread is:” + Thread.currentThread().getName()); CDS.idle (private_idle); } } // end run } // end Idler // CDS.java - Useful class for Concurrent and Distributed Systems public class CDS { public static void idle (int millisecs) { Thread mainThread = Thread.currentThread(); System.out.println(mainThread.getName() + ": About to sleep"); try { 3 Thread.sleep(millisecs); } catch (InterruptedException e) { } System.out.println (mainThread.getName() + ": Woken up"); } // end idle } // end CD (a) Run the “RunIdlers” program and verify the output. (b) Alter the run() methods so that the private variable is used to specify the maximum length of time that the process sleeps (rather than the actual time) on each iteration of the loop. That is let it sleep a random length of time up to the maximum. You can use Math.random() to simulate random lengths of time. (c) Put a loop in the main() method of RunIdlers which occasionally prints out a statement to show that RunIdlers can execute concurrently with the two threads. Question 4 – More Threads The application below consists of classes ThreadDemo and MyThread. Class ThreadDemo drives the application by creating a MyThread object and starting it. The ThreadDemo class then prints the “squares times table” for the numbers 1..50. In concurrent fashion MyThread overrides Thread's run() method to print (on the standard output stream) a right-angle triangle composed of asterisk characters. // ThreadDemo.java class ThreadDemo { public static void main (String [] args) { MyThread mt = new MyThread (); mt.start (); for (int i = 0; i < 50; i++) System.out.println ("i = " + i + ", i * i = " + i * i); } } class MyThread extends Thread { public void run () { for (int count = 1, row = 1; row < 20; row++, count++) { for (int i = 0; i < count; i++) System.out.print ('*'); System.out.print ('\n'); } } } (a) Run this program and verify the output. (b) Incorporate delays to try and have the triangle printed before and then after the square. 4 Question 5 – Threads (Unpredictable output) In the example below, we'll create and start two threads, each of which prints two lines to System.out: public class TwoThreads { public static class Thread1 extends Thread { public void run() { System.out.println("A"); System.out.println("B"); } } public static class Thread2 extends Thread { public void run() { System.out.println("1"); System.out.println("2") } } public static void main(String[] args) { new Thread1().start(); new Thread2().start(); } } We have no idea in what order the lines will execute, except that "1" will be printed before "2" and "A" before "B." The output could be any one of the following: •12AB •1A2B •1AB2 •A12B •A1B2 •AB12 (a) Verify that this is the case. (b) Put in appropriate delays to ensure the letters are output before the numbers. (c) Make both threads print their output forever and see the results. Note. You will need to experiment with random delays at different points in the code to get the output you require. END 5